OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "nacl_app/sprite.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 namespace { | |
10 const uint32_t kRedBlueMask = 0x00FF00FF; | |
11 const uint32_t kGreenMask = 0x0000FF00; | |
12 const uint32_t kAlphaMask = 0xFF000000; | |
13 const uint32_t k8x2Scale = 0x800080; | |
14 const uint32_t kPixelOne = 0xFF; | |
15 const uint32_t kAlphaShift = 24; | |
16 | |
17 // Use Blinn & Smith's method of scaling by 256, instead of 255. Blends two | |
18 // colour channels simultaneously: the R and B of an ARGB pixel. | |
19 // This code expects rb as a packed 16:16 fixed point number, and a as an 8-bit | |
20 // value in [0..255]. | |
21 inline uint32_t Blend8x2(uint32_t rb, uint32_t a) { | |
22 rb &= kRedBlueMask; | |
23 uint32_t blend = a * rb + k8x2Scale; // Scale by 256. | |
24 return (blend + ((blend >> 8) & kRedBlueMask)) >> 8 & kRedBlueMask; | |
25 } | |
26 | |
27 } // namespace | |
28 | |
29 namespace flocking_geese { | |
30 | |
31 Sprite::Sprite(uint32_t* pixel_buffer, | |
32 const pp::Size& size, | |
33 int32_t row_bytes) { | |
34 SetPixelBuffer(pixel_buffer, size, row_bytes); | |
35 } | |
36 | |
37 void Sprite::SetPixelBuffer(uint32_t* pixel_buffer, | |
38 const pp::Size& size, | |
39 int32_t row_bytes) { | |
40 pixel_buffer_.reset(pixel_buffer); | |
41 pixel_buffer_size_ = size; | |
42 row_bytes_ = row_bytes ? row_bytes : size.width() * sizeof(uint32_t); | |
43 } | |
44 | |
45 void Sprite::CompositeFromRectToPoint(const pp::Rect& src_rect, | |
46 uint32_t* dest_pixel_buffer, | |
47 const pp::Rect& dest_bounds, | |
48 int32_t dest_row_bytes, | |
49 const pp::Point& dest_point) const { | |
50 // Clip the source rect to the source image bounds. | |
51 pp::Rect src_bounds(pp::Point(), size()); | |
52 pp::Rect src_rect_clipped(src_rect.Intersect(src_bounds)); | |
53 if (src_rect_clipped.IsEmpty()) | |
54 return; | |
55 | |
56 // Create a clipped rect in the destination coordinate space that contains the | |
57 // final image. | |
58 pp::Rect draw_rect(dest_point, src_rect_clipped.size()); | |
59 pp::Rect draw_rect_clipped(dest_bounds.Intersect(draw_rect)); | |
60 if (draw_rect_clipped.IsEmpty()) | |
61 return; | |
62 // Transform the destination rectangle back to the source image coordinate | |
63 // system: Translate(-dest_point) . Translate(src_rect_clipped.origin). | |
64 pp::Point src_offset(draw_rect_clipped.point()); | |
65 src_offset -= dest_point; | |
66 src_rect_clipped.Offset(src_offset); | |
67 src_rect_clipped.set_size(draw_rect_clipped.size()); | |
68 size_t src_byte_offset = src_rect_clipped.x() * sizeof(uint32_t) + | |
69 src_rect_clipped.y() * row_bytes_; | |
70 const uint8_t* src_pixels = | |
71 reinterpret_cast<const uint8_t*>(pixel_buffer_.get()) + src_byte_offset; | |
72 | |
73 if (dest_row_bytes == 0) | |
74 dest_row_bytes = dest_bounds.width() * sizeof(uint32_t); | |
75 size_t dest_byte_offset = draw_rect_clipped.point().x() * sizeof(uint32_t) + | |
76 draw_rect_clipped.point().y() * dest_row_bytes; | |
77 uint8_t* dest_pixels = reinterpret_cast<uint8_t*>(dest_pixel_buffer) + | |
78 dest_byte_offset; | |
79 | |
80 // All the pointers are set up, now do the SOver. Note that the only pre- | |
81 // multiplied alpha formats are supported. | |
82 for (int32_t y = 0; y < src_rect_clipped.height(); ++y) { | |
83 const uint32_t* src_scanline = | |
84 reinterpret_cast<const uint32_t*>(src_pixels); | |
85 uint32_t* dest_scanline = reinterpret_cast<uint32_t*>(dest_pixels); | |
86 for (int32_t x = 0; x < src_rect_clipped.width(); ++x) { | |
87 uint32_t src = *src_scanline++; | |
88 uint32_t dst = *dest_scanline; | |
89 uint32_t alpha = (src >> kAlphaShift) & kPixelOne; | |
90 uint32_t one_minus_alpha = kPixelOne - alpha; | |
91 // Compute RB and G separately: this allows for SIMD-like behaviour | |
92 // when multiplying the channels by alpha. Note that over-saturated | |
93 // pixels will wrap to 0 and not clamp. | |
94 uint32_t dst_rb = Blend8x2(dst, one_minus_alpha); | |
95 uint32_t dst_ga = Blend8x2(dst >> 8, one_minus_alpha) << 8; | |
96 *dest_scanline++ = src + dst_rb + dst_ga; | |
97 } | |
98 src_pixels += row_bytes_; | |
99 dest_pixels += dest_row_bytes; | |
100 } | |
101 } | |
102 | |
103 } // namespace flocking_geese | |
104 | |
OLD | NEW |