roo_display
API Documentation for roo_display
Loading...
Searching...
No Matches
streamable.h
Go to the documentation of this file.
1#pragma once
2
8
9namespace roo_display {
10
11/// Stream of pixels in row-major order.
13 public:
14 /// Read up to `size` pixels into `buf`.
15 virtual void Read(Color* buf, uint16_t size) = 0;
16
17 /// Skip `count` pixels.
18 virtual void Skip(uint32_t count) {
20 while (count > kPixelWritingBufferSize) {
23 }
24 Read(buf, count);
25 }
26
27 virtual ~PixelStream() {}
28};
29
30namespace internal {
31
32inline void fillReplaceRect(DisplayOutput& output, const Box& extents,
35 output.setAddress(extents, mode);
36 uint32_t count = extents.area();
37 while (count > 0) {
38 uint32_t n = count;
40 stream->Read(buf, n);
41 output.write(buf, n);
42 count -= n;
43 }
44}
45
46inline void fillPaintRectOverOpaqueBg(DisplayOutput& output, const Box& extents,
48 BlendingMode mode) {
50 output.setAddress(extents, mode);
51 uint32_t count = extents.area();
52 do {
54 if (n > count) n = count;
55 stream->Read(buf, n);
56 for (int i = 0; i < n; i++) buf[i] = AlphaBlendOverOpaque(bgColor, buf[i]);
57 output.write(buf, n);
58 count -= n;
59 } while (count > 0);
60}
61
62inline void fillPaintRectOverBg(DisplayOutput& output, const Box& extents,
64 BlendingMode mode) {
66 output.setAddress(extents, mode);
67 uint32_t count = extents.area();
68 do {
70 if (n > count) n = count;
71 stream->Read(buf, n);
72 for (int i = 0; i < n; ++i) {
74 }
75 output.write(buf, n);
76 count -= n;
77 } while (count > 0);
78}
79
80// Assumes no bgcolor.
81inline void writeRectVisible(DisplayOutput& output, const Box& extents,
83 // TODO(dawidk): need to optimize this.
85 BufferedPixelWriter writer(output, mode);
86 uint32_t remaining = extents.area();
88 for (int16_t j = extents.yMin(); j <= extents.yMax(); ++j) {
89 for (int16_t i = extents.xMin(); i <= extents.xMax(); ++i) {
91 idx = 0;
94 stream->Read(buf, n);
95 remaining -= n;
96 }
97 Color color = buf[idx++];
98 if (color.a() != 0) {
99 writer.writePixel(i, j, color);
100 }
101 }
102 }
103}
104
106 const Box& extents, Color bgcolor,
108 BlendingMode mode) {
109 // TODO(dawidk): need to optimize this.
111 BufferedPixelWriter writer(output, mode);
112 uint32_t remaining = extents.area();
114 for (int16_t j = extents.yMin(); j <= extents.yMax(); ++j) {
115 for (int16_t i = extents.xMin(); i <= extents.xMax(); ++i) {
117 idx = 0;
120 stream->Read(buf, n);
121 }
122 Color color = buf[idx++];
123 if (color.a() != 0) {
124 writer.writePixel(i, j, AlphaBlendOverOpaque(bgcolor, color));
125 }
126 }
127 }
128}
129
130inline void writeRectVisibleOverBg(DisplayOutput& output, const Box& extents,
132 BlendingMode mode) {
133 // TODO(dawidk): need to optimize this.
135 BufferedPixelWriter writer(output, mode);
136 uint32_t remaining = extents.area();
138 for (int16_t j = extents.yMin(); j <= extents.yMax(); ++j) {
139 for (int16_t i = extents.xMin(); i <= extents.xMax(); ++i) {
141 idx = 0;
144 stream->Read(buf, n);
145 }
146 Color color = buf[idx++];
147 if (color.a() != 0) {
148 writer.writePixel(i, j, AlphaBlend(bgcolor, color));
149 }
150 }
151 }
152}
153
154// This function will fill in the specified rectangle using the most appropriate
155// method given the stream's transparency mode.
156inline void FillRectFromStream(DisplayOutput& output, const Box& extents,
159 TransparencyMode transparency) {
161 transparency == TransparencyMode::kNone) {
162 if (bgcolor.a() == 0 || transparency == TransparencyMode::kNone) {
163 fillReplaceRect(output, extents, stream, blending_mode);
164 } else if (bgcolor.a() == 0xFF) {
165 fillPaintRectOverOpaqueBg(output, extents, bgcolor, stream,
167 } else {
169 }
170 } else {
171 if (bgcolor.a() == 0) {
172 writeRectVisible(output, extents, stream, blending_mode);
173 } else if (bgcolor.a() == 0xFF) {
176 } else {
178 }
179 }
180};
181
183 public:
184 BufferingStream(std::unique_ptr<PixelStream> stream, uint32_t count)
185 : stream_(std::move(stream)),
186 remaining_(count),
188
190 if (idx_ >= kPixelWritingBufferSize) {
191 idx_ = 0;
192 fetch();
193 }
194 return buf_[idx_++];
195 }
196
197 // void read(Color* buf, uint16_t count) {
198 // while (count-- > 0) {
199 // *buf++ = next();
200 // }
201 // }
202
203 // void blend(Color* buf, uint16_t count) {
204 // while (count-- > 0) {
205 // *buf = AlphaBlend(*buf, next());
206 // buf++;
207 // }
208 // return;
209 // }
210
211 void read(Color* buf, uint16_t count) {
212 if (idx_ >= kPixelWritingBufferSize) {
213 idx_ = 0;
214 fetch();
215 }
216 const Color* in = buf_ + idx_;
218 while (true) {
219 if (count <= batch) {
220 idx_ += count;
221 memcpy(buf, in, count * sizeof(Color));
222 return;
223 }
224 memcpy(buf, in, batch * sizeof(Color));
225 count -= batch;
226 buf += batch;
227 idx_ = 0;
228 in = buf_;
229 batch = fetch();
230 }
231 }
232
234 if (idx_ >= kPixelWritingBufferSize) {
235 idx_ = 0;
236 fetch();
237 }
238 const Color* in = buf_ + idx_;
240 while (true) {
241 if (count <= batch) {
242 idx_ += count;
244 return;
245 }
246 count -= batch;
248 buf += batch;
249 idx_ = 0;
250 in = buf_;
251 batch = fetch();
252 }
253 }
254
255 void skip(uint32_t count) {
257 if (count < buffered) {
258 idx_ += count;
259 return;
260 }
261 count -= buffered;
262 idx_ = 0;
263 do {
264 uint16_t n = fetch();
265 if (count < n) {
266 idx_ = count;
267 return;
268 }
269 count -= n;
270 } while (remaining_ > 0);
271 }
272
273 private:
274 uint16_t fetch() {
276 if (n > remaining_) n = remaining_;
277 stream_->Read(buf_, n);
278 remaining_ -= n;
279 return n;
280 }
281
282 std::unique_ptr<PixelStream> stream_;
283 uint32_t remaining_;
285 int idx_;
286};
287
288// Restricts the stream to the specified sub-rectangle. More specifically,
289// since streams don't know their rectangle dimension, it:
290// * assumes that the delegate stream has been already skipped to the right
291// starting place, so that the first next() call would return the pixel
292// corresponding to the top-left corner of the sub-rectanble
293// * then, returns the specified number of colored pixels, and then skips
294// by specified amount (to get to the next 'line') in the delegate stream.
295// The caller should guarantee that the sum of these two quantities
296// (width and width_skip) is equal to the pixel width of the image represented
297// by the underlying stream.
298template <typename Delegate>
300 public:
303 : stream_(std::move(delegate)),
304 x_(0),
305 width_(width),
306 width_skip_(width_skip),
307 remaining_(count),
309
311
312 void Read(Color* buf, uint16_t count) override {
313 do {
314 if (x_ >= width_) {
315 dskip(width_skip_);
316 x_ = 0;
317 }
318 uint16_t n = width_ - x_;
319 if (n > count) n = count;
320 uint16_t read = dnext(buf, n);
321 buf += read;
322 count -= read;
323 x_ += read;
324 } while (count > 0);
325 }
326
327 // void skip(uint32_t count) {
328 // // TODO: optimize
329 // for (int i = 0; i < count; i++) next();
330 // }
331
332 private:
333 // Color next() {
334 // if (x_ >= width_) {
335 // dskip(width_skip_);
336 // x_ = 0;
337 // }
338 // Color result = dnext();
339 // ++x_;
340 // return result;
341 // }
342
343 void dskip(uint32_t count) {
345 if (count <= buffered) {
346 idx_ += count;
347 return;
348 }
349 count -= buffered;
351 if (count >= kPixelWritingBufferSize / 2) {
352 stream_.Skip(count);
353 remaining_ -= count;
354 return;
355 }
356 uint16_t n = kPixelWritingBufferSize;
357 if (n > remaining_) n = remaining_;
358 stream_.Read(buf_, n);
359 remaining_ -= n;
360 idx_ = count;
361 }
362
363 uint16_t dnext(Color* buf, int16_t count) {
364 if (idx_ >= kPixelWritingBufferSize) {
365 uint16_t n = kPixelWritingBufferSize;
366 if (n > remaining_) n = remaining_;
367 stream_.Read(buf_, n);
368 idx_ = 0;
369 remaining_ -= n;
370 }
371 if (count > kPixelWritingBufferSize - idx_) {
372 count = kPixelWritingBufferSize - idx_;
373 }
374 memcpy(buf, buf_ + idx_, count * sizeof(Color));
375 idx_ += count;
376 return count;
377 }
378
379 SubRectangleStream(const SubRectangleStream&) = delete;
380
381 Delegate stream_;
382 int16_t x_;
383 const int16_t width_;
384 const int16_t width_skip_;
385
386 uint32_t remaining_;
387 Color buf_[kPixelWritingBufferSize];
388 int idx_;
389};
390
391template <typename Stream>
393 const Box& extents,
394 const Box& bounds) {
395 int line_offset = extents.width() - bounds.width();
396 int xoffset = bounds.xMin() - extents.xMin();
397 int yoffset = bounds.yMin() - extents.yMin();
398 uint32_t skipped = yoffset * extents.width() + xoffset;
399 stream.Skip(skipped);
400 return SubRectangleStream<Stream>(std::move(stream), extents.area() - skipped,
401 bounds.width(), line_offset);
402}
403
404} // namespace internal
405
406template <typename Stream>
407/// Create a pixel stream over a sub-rectangle of a larger stream.
408inline std::unique_ptr<PixelStream> SubRectangle(Stream stream,
409 const Box& extents,
410 const Box& bounds) {
411 int line_offset = extents.width() - bounds.width();
412 int xoffset = bounds.xMin() - extents.xMin();
413 int yoffset = bounds.yMin() - extents.yMin();
414 uint32_t skipped = yoffset * extents.width() + xoffset;
415 stream.Skip(skipped);
416 return std::unique_ptr<PixelStream>(new internal::SubRectangleStream<Stream>(
417 std::move(stream), extents.area() - skipped, bounds.width(),
418 line_offset));
419}
420
421/// Drawable that can provide a sequential pixel stream.
422///
423/// Streamables allow the renderer to efficiently draw clipped rectangles and
424/// blend pixel data without per-pixel virtual calls. This is commonly used by
425/// images and offscreen buffers, and it is also the base for Rasterizable.
426class Streamable : public virtual Drawable {
427 public:
428 /// Create a stream covering the full `extents()`.
429 virtual std::unique_ptr<PixelStream> createStream() const = 0;
430
431 /// Create a stream for the given clipped bounds.
432 virtual std::unique_ptr<PixelStream> createStream(
433 const Box& clip_box) const = 0;
434
435 /// Return the transparency mode for pixels in this stream.
436 ///
437 /// This is an optimization hint. The default is `TransparencyMode::kFull`,
438 /// which is always safe. If pixels are guaranteed fully opaque or 1-bit
439 /// alpha, return `TransparencyMode::kNone` or `TransparencyMode::kCrude` to
440 /// enable faster blending paths.
444
445 private:
446 void drawTo(const Surface& s) const override {
447 Box ext = extents();
448 Box bounds = Box::Intersect(s.clip_box().translate(-s.dx(), -s.dy()), ext);
449 if (bounds.empty()) return;
450 std::unique_ptr<PixelStream> stream;
451 if (ext.width() == bounds.width() && ext.height() == bounds.height()) {
453 } else {
454 stream = createStream(bounds);
455 }
456 internal::FillRectFromStream(s.out(), bounds.translate(s.dx(), s.dy()),
457 stream.get(), s.bgcolor(), s.fill_mode(),
459 }
460};
461
462/// Convenience wrapper for images backed by a byte stream.
463template <typename Iterable, typename ColorMode, typename StreamType>
465 public:
466 /// Construct from width/height and a resource.
468 const ColorMode& color_mode = ColorMode())
469 : SimpleStreamable(Box(0, 0, width - 1, height - 1), std::move(resource),
470 std::move(color_mode)) {}
471
472 /// Construct from extents and a resource.
476
477 /// Construct from extents, anchor extents, and a resource.
479 const ColorMode& color_mode = ColorMode())
480 : extents_(std::move(extents)),
481 anchor_extents_(anchor_extents),
482 resource_(std::move(resource)),
483 color_mode_(color_mode) {}
484
485 /// Set the color mode.
486 void setColorMode(const ColorMode& color_mode) { color_mode_ = color_mode; }
487
488 /// Return extents of the image.
489 Box extents() const override { return extents_; }
490
491 /// Return anchor extents used for alignment.
492 Box anchorExtents() const override { return anchor_extents_; }
493
494 /// Access underlying resource.
495 const Iterable& resource() const { return resource_; }
496 /// Access color mode (const).
497 const ColorMode& color_mode() const { return color_mode_; }
498 /// Access color mode (mutable).
499 ColorMode& color_mode() { return color_mode_; }
500
501 /// Create a pixel stream for the full extents.
502 std::unique_ptr<PixelStream> createStream() const override {
503 return std::unique_ptr<PixelStream>(
504 new StreamType(resource_.iterator(), color_mode_));
505 }
506
507 /// Create a pixel stream for a clipped box.
508 std::unique_ptr<PixelStream> createStream(const Box& bounds) const override {
509 return SubRectangle(StreamType(resource_.iterator(), color_mode_),
510 extents(), bounds);
511 }
512
513 /// Create the raw stream type.
514 std::unique_ptr<StreamType> createRawStream() const {
515 return std::unique_ptr<StreamType>(
516 new StreamType(resource_.iterator(), color_mode_));
517 }
518
519 /// Return transparency mode derived from color mode.
521 return color_mode_.transparency();
522 }
523
524 private:
525 Box extents_;
526 Box anchor_extents_;
527
528 Iterable resource_;
529 ColorMode color_mode_;
530};
531
532} // namespace roo_display
BufferedRectWriter & writer
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 xMax() const
Maximum x (inclusive).
Definition box.h:71
bool empty() const
Return whether the box is empty.
Definition box.h:62
int16_t height() const
Height in pixels (inclusive coordinates).
Definition box.h:80
Box translate(int16_t x_offset, int16_t y_offset) const
Return a translated copy of this box.
Definition box.h:127
int16_t yMax() const
Maximum y (inclusive).
Definition box.h:74
int32_t area() const
Area in pixels.
Definition box.h:83
static Box Intersect(const Box &a, const Box &b)
Return the intersection of two boxes (may be empty).
Definition box.h:25
int16_t yMin() const
Minimum y (inclusive).
Definition box.h:68
Buffered writer for arbitrary pixels with per-pixel colors.
ARGB8888 color stored as a 32-bit unsigned integer.
Definition color.h:16
The abstraction for drawing to a display.
Definition device.h:15
virtual void write(Color *color, uint32_t pixel_count)=0
Write pixels into the current address window.
void setAddress(const Box &bounds, BlendingMode blending_mode)
Convenience overload for setAddress() using a Box.
Definition device.h:45
Interface for objects that can be drawn to an output device.
Definition drawable.h:229
virtual Box extents() const =0
Return the bounding box encompassing all pixels that need to be drawn.
Stream of pixels in row-major order.
Definition streamable.h:12
virtual void Skip(uint32_t count)
Skip count pixels.
Definition streamable.h:18
virtual void Read(Color *buf, uint16_t size)=0
Read up to size pixels into buf.
Convenience wrapper for images backed by a byte stream.
Definition streamable.h:464
TransparencyMode getTransparencyMode() const override
Return transparency mode derived from color mode.
Definition streamable.h:520
const Iterable & resource() const
Access underlying resource.
Definition streamable.h:495
Box extents() const override
Return extents of the image.
Definition streamable.h:489
SimpleStreamable(Box extents, Iterable resource, const ColorMode &color_mode=ColorMode())
Construct from extents and a resource.
Definition streamable.h:473
SimpleStreamable(Box extents, Box anchor_extents, Iterable resource, const ColorMode &color_mode=ColorMode())
Construct from extents, anchor extents, and a resource.
Definition streamable.h:478
Box anchorExtents() const override
Return anchor extents used for alignment.
Definition streamable.h:492
ColorMode & color_mode()
Access color mode (mutable).
Definition streamable.h:499
std::unique_ptr< PixelStream > createStream(const Box &bounds) const override
Create a pixel stream for a clipped box.
Definition streamable.h:508
std::unique_ptr< StreamType > createRawStream() const
Create the raw stream type.
Definition streamable.h:514
const ColorMode & color_mode() const
Access color mode (const).
Definition streamable.h:497
void setColorMode(const ColorMode &color_mode)
Set the color mode.
Definition streamable.h:486
SimpleStreamable(int16_t width, int16_t height, Iterable resource, const ColorMode &color_mode=ColorMode())
Construct from width/height and a resource.
Definition streamable.h:467
std::unique_ptr< PixelStream > createStream() const override
Create a pixel stream for the full extents.
Definition streamable.h:502
Drawable that can provide a sequential pixel stream.
Definition streamable.h:426
virtual std::unique_ptr< PixelStream > createStream() const =0
Create a stream covering the full extents().
virtual TransparencyMode getTransparencyMode() const
Return the transparency mode for pixels in this stream.
Definition streamable.h:441
virtual std::unique_ptr< PixelStream > createStream(const Box &clip_box) const =0
Create a stream for the given clipped bounds.
Low-level handle used to draw to an underlying device.
Definition drawable.h:60
int16_t dy() const
Return the y offset to apply to drawn objects.
Definition drawable.h:128
Color bgcolor() const
Return the background color used for blending.
Definition drawable.h:140
int16_t dx() const
Return the x offset to apply to drawn objects.
Definition drawable.h:125
BlendingMode blending_mode() const
Return the default blending mode for drawing.
Definition drawable.h:162
FillMode fill_mode() const
Return the fill mode the drawable should observe. FillMode::kVisible If FillMode::kExtents,...
Definition drawable.h:151
DisplayOutput & out() const
Return the device output.
Definition drawable.h:119
void read(Color *buf, uint16_t count)
Definition streamable.h:211
void blend(Color *buf, uint16_t count, BlendingMode blending_mode)
Definition streamable.h:233
BufferingStream(std::unique_ptr< PixelStream > stream, uint32_t count)
Definition streamable.h:184
SubRectangleStream(SubRectangleStream &&)=default
void Read(Color *buf, uint16_t count) override
Read up to size pixels into buf.
Definition streamable.h:312
SubRectangleStream(Delegate delegate, uint32_t count, int16_t width, int16_t width_skip)
Definition streamable.h:301
SubRectangleStream< Stream > MakeSubRectangle(Stream stream, const Box &extents, const Box &bounds)
Definition streamable.h:392
void writeRectVisible(DisplayOutput &output, const Box &extents, PixelStream *stream, BlendingMode mode)
Definition streamable.h:81
void fillPaintRectOverBg(DisplayOutput &output, const Box &extents, Color bgcolor, PixelStream *stream, BlendingMode mode)
Definition streamable.h:62
void writeRectVisibleOverBg(DisplayOutput &output, const Box &extents, Color bgcolor, PixelStream *stream, BlendingMode mode)
Definition streamable.h:130
void writeRectVisibleOverOpaqueBg(DisplayOutput &output, const Box &extents, Color bgcolor, PixelStream *stream, BlendingMode mode)
Definition streamable.h:105
void fillReplaceRect(DisplayOutput &output, const Box &extents, PixelStream *stream, BlendingMode mode)
Definition streamable.h:32
void fillPaintRectOverOpaqueBg(DisplayOutput &output, const Box &extents, Color bgColor, PixelStream *stream, BlendingMode mode)
Definition streamable.h:46
void FillRectFromStream(DisplayOutput &output, const Box &extents, PixelStream *stream, Color bgcolor, FillMode fill_mode, BlendingMode blending_mode, TransparencyMode transparency)
Definition streamable.h:156
Defines 140 opaque HTML named colors.
BlendingMode
Porter-Duff style blending modes.
Definition blending.h:17
void ApplyBlendingInPlace(BlendingMode mode, Color *dst, const Color *src, int16_t count)
Definition blending.h:561
Color AlphaBlend(Color bgc, Color fgc)
Definition blending.h:598
static const uint8_t kPixelWritingBufferSize
decltype(std::declval< Resource >().iterator()) StreamType
Stream type produced by a resource iterable.
Definition raster.h:22
TransparencyMode
Transparency information for a stream or color mode.
Definition blending.h:103
@ kNone
All colors are fully opaque.
@ kFull
Colors may include partial transparency (alpha channel).
Color AlphaBlendOverOpaque(Color bgc, Color fgc)
Definition blending.h:465
std::unique_ptr< PixelStream > SubRectangle(Stream stream, const Box &extents, const Box &bounds)
Create a pixel stream over a sub-rectangle of a larger stream.
Definition streamable.h:408
FillMode
Specifies whether a Drawable should fill its entire extents box, including fully transparent pixels.
Definition drawable.h:15
@ kExtents
Fill the entire extents box (possibly with fully transparent pixels).
Color bgcolor
Definition smooth.cpp:889
FillMode fill_mode
Definition smooth.cpp:887
BlendingMode blending_mode
Definition smooth.cpp:888