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 "experimental/conways_life/stamp.h" | |
6 | |
7 #include <algorithm> | |
8 #include <cstring> | |
9 | |
10 namespace { | |
11 const int32_t kMinimumStampDimension = 3; | |
12 const char kStampLineSeparator = '\n'; | |
13 const char kStampAliveCharacter = '*'; | |
14 const char kStampDeadCharacter = '.'; | |
15 const uint32_t kWhiteColor = 0xFFFFFFFF; | |
16 const uint32_t kBlackColor = 0xFF000000; | |
17 | |
18 // Do a simple copy composite from src_buffer into dst_buffer. Copy the pixels | |
19 // contained in |src_rect| to |dst_loc|. This assumes that all the necessary | |
20 // cropping and clipping has been done, and that all the buffer pointers are | |
21 // valid. | |
22 template <class PixelT> void CopyCompositeToPoint( | |
23 const PixelT* src_buffer, | |
24 int src_row_width, | |
25 const pp::Rect& src_rect, | |
26 PixelT* dst_buffer, | |
27 int dst_row_width, | |
28 const pp::Point& dst_loc) { | |
29 const PixelT* src = src_buffer + src_rect.x() + src_rect.y() * src_row_width; | |
30 PixelT* dst = dst_buffer + dst_loc.x() + dst_loc.y() * dst_row_width; | |
31 for (int y = 0; y < src_rect.height(); ++y) { | |
32 memcpy(dst, src, src_rect.width() * sizeof(PixelT)); | |
33 src += src_row_width; | |
34 dst += dst_row_width; | |
35 } | |
36 } | |
37 } // namespace | |
38 | |
39 namespace life { | |
40 Stamp::Stamp() | |
41 : size_(kMinimumStampDimension, kMinimumStampDimension), | |
42 stamp_offset_(0, 0) { | |
43 // Build the default stamp. | |
44 int buffer_size = size_.GetArea(); | |
45 pixel_buffer_.resize(buffer_size); | |
46 cell_buffer_.resize(buffer_size); | |
47 std::fill(&pixel_buffer_[0], | |
48 &pixel_buffer_[0] + buffer_size, kBlackColor); | |
49 std::fill(&cell_buffer_[0], | |
50 &cell_buffer_[0] + buffer_size, 1); | |
51 } | |
52 | |
53 bool Stamp::InitFromDescription(const std::string& stamp_description) { | |
54 // Compute the width and height of the stamp description. | |
55 size_t eol_pos = stamp_description.find(kStampLineSeparator); | |
56 pp::Size new_size; | |
57 if (eol_pos == std::string::npos) { | |
58 new_size.set_width(stamp_description.size()); | |
59 new_size.set_height(1); | |
60 } else { | |
61 new_size.set_width(eol_pos); | |
62 // Count up the number of lines. | |
63 int count = 0; | |
64 do { | |
65 ++count; | |
66 eol_pos = stamp_description.find(kStampLineSeparator, eol_pos + 1); | |
67 } while (eol_pos != std::string::npos); | |
68 new_size.set_height(count); | |
69 } | |
70 int buffer_size = new_size.GetArea(); | |
71 if (buffer_size <= 0) | |
72 return false; | |
73 size_ = new_size; | |
74 pixel_buffer_.resize(buffer_size); | |
75 cell_buffer_.resize(buffer_size); | |
76 int buffer_index = 0; | |
77 for (size_t i = 0; i < stamp_description.size(); ++i) { | |
78 switch (stamp_description[i]) { | |
79 case kStampAliveCharacter: | |
80 pixel_buffer_[buffer_index] = kBlackColor; | |
81 cell_buffer_[buffer_index] = 1; | |
82 ++buffer_index; | |
83 break; | |
84 case kStampDeadCharacter: | |
85 pixel_buffer_[buffer_index] = kWhiteColor; | |
86 cell_buffer_[buffer_index] = 0; | |
87 ++buffer_index; | |
88 break; | |
89 case kStampLineSeparator: | |
90 // Ignore these. | |
91 break; | |
92 default: | |
93 // Invalid character - error? | |
94 ++buffer_index; | |
95 break; | |
96 } | |
97 } | |
98 return true; | |
99 } | |
100 | |
101 Stamp::~Stamp() { | |
102 } | |
103 | |
104 void Stamp::StampAtPointInBuffers(const pp::Point& point, | |
105 uint32_t* dest_pixel_buffer, | |
106 uint8_t* dest_cell_buffer, | |
107 const pp::Size& buffer_size) const { | |
108 pp::Rect src_rect_clipped(pp::Point(), size()); | |
109 if (src_rect_clipped.IsEmpty()) | |
110 return; | |
111 | |
112 pp::Point dest_point(point); | |
113 dest_point -= stamp_offset(); | |
114 // Create a clipped rect in the destination coordinate space that contains the | |
115 // final image. | |
116 pp::Rect dest_bounds(pp::Point(), buffer_size); | |
117 pp::Rect draw_rect(dest_point, src_rect_clipped.size()); | |
118 pp::Rect draw_rect_clipped(dest_bounds.Intersect(draw_rect)); | |
119 if (draw_rect_clipped.IsEmpty()) | |
120 return; | |
121 // Transform the destination rectangle back to the source image coordinate | |
122 // system: Translate(-dest_point) . Translate(src_rect_clipped.origin). | |
123 pp::Point src_offset(draw_rect_clipped.point()); | |
124 src_offset -= dest_point; | |
125 src_rect_clipped.Offset(src_offset); | |
126 src_rect_clipped.set_size(draw_rect_clipped.size()); | |
127 if (dest_pixel_buffer) { | |
128 CopyCompositeToPoint(&pixel_buffer_[0], | |
129 size().width(), | |
130 src_rect_clipped, | |
131 dest_pixel_buffer, | |
132 buffer_size.width(), | |
133 dest_point); | |
134 } | |
135 if (dest_cell_buffer) { | |
136 CopyCompositeToPoint(&cell_buffer_[0], | |
137 size().width(), | |
138 src_rect_clipped, | |
139 dest_cell_buffer, | |
140 buffer_size.width(), | |
141 dest_point); | |
142 } | |
143 } | |
144 } // namespace life | |
OLD | NEW |