Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(542)

Side by Side Diff: experimental/conways_life/life.cc

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « experimental/conways_life/life.h ('k') | experimental/conways_life/life.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/life.h"
6
7 #include <stdio.h>
8 #include <algorithm>
9 #include <cmath>
10 #include <string>
11
12 #include "experimental/conways_life/scoped_pixel_lock.h"
13 #include "experimental/conways_life/threading/scoped_mutex_lock.h"
14 #include "ppapi/cpp/size.h"
15
16 namespace {
17 const unsigned int kInitialRandSeed = 0xC0DE533D;
18 const int kMaxNeighbourCount = 8;
19 // Offests into the autmaton rule lookup table.
20 const size_t kKeepAliveRuleOffset = 9;
21 const size_t kBirthRuleOffset = 0;
22
23 inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
24 return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
25 }
26
27 // Map of neighboring colors.
28 const uint32_t kNeighborColors[] = {
29 MakeRGBA(0xFF, 0xFF, 0xFF, 0xFF), // Dead with 0 neighbours.
30 MakeRGBA(0xE0, 0xE0, 0xE0, 0xFF), // Dead with 1 neighbour.
31 MakeRGBA(0xC0, 0xC0, 0xC0, 0xFF), // 2 neighbours.
32 MakeRGBA(0xA0, 0xA0, 0xA0, 0xFF), // 3
33 MakeRGBA(0x80, 0x80, 0x80, 0xFF), // 4
34 MakeRGBA(0x60, 0x60, 0x60, 0xFF), // 5
35 MakeRGBA(0x40, 0x40, 0x40, 0xFF), // 6
36 MakeRGBA(0x20, 0x20, 0x20, 0xFF), // 7
37 MakeRGBA(0x10, 0x10, 0x10, 0xFF), // 8
38 MakeRGBA(0x00, 0x00, 0x00, 0xFF), // Alive with 0 neighbours.
39 MakeRGBA(0x10, 0x10, 0x10, 0xFF), // Alive with 1 neighbours.
40 MakeRGBA(0x20, 0x20, 0x20, 0xFF), // 2 neighbours.
41 MakeRGBA(0x30, 0x30, 0x30, 0xFF), // 3
42 MakeRGBA(0x40, 0x40, 0x40, 0xFF), // 4
43 MakeRGBA(0x60, 0x60, 0x60, 0xFF), // 5
44 MakeRGBA(0x80, 0x80, 0x80, 0xFF), // 6
45 MakeRGBA(0xC0, 0xC0, 0xC0, 0xFF), // 7
46 MakeRGBA(0xF0, 0xF0, 0xF0, 0xFF) // 8
47 };
48 } // namespace
49
50 namespace life {
51 Life::Life() : life_simulation_thread_(NULL),
52 sim_state_condition_(kSimulationStopped),
53 width_(0),
54 height_(0),
55 simulation_mode_(kPaused),
56 random_bits_(kInitialRandSeed),
57 cell_in_(NULL),
58 cell_out_(NULL) {
59 pthread_mutex_init(&life_simulation_mutex_, NULL);
60 // Set up the default life rules table. |life_rules_table_| is a look-up
61 // table, index by the number of living neighbours of a cell. Indices [0..8]
62 // represent the rules when the cell being examined is dead; indices [9..17]
63 // represnt the rules when the cell is alive.
64 life_rules_table_.resize(kMaxNeighbourCount * 2 + 1);
65 std::fill(&life_rules_table_[0],
66 &life_rules_table_[0] + life_rules_table_.size(),
67 0);
68 life_rules_table_[kBirthRuleOffset + 3] = 1;
69 life_rules_table_[kKeepAliveRuleOffset + 2] = 1;
70 life_rules_table_[kKeepAliveRuleOffset + 3] = 1;
71 }
72
73 Life::~Life() {
74 set_is_simulation_running(false);
75 if (life_simulation_thread_) {
76 pthread_join(life_simulation_thread_, NULL);
77 }
78 DeleteCells();
79 pthread_mutex_destroy(&life_simulation_mutex_);
80 }
81
82 void Life::StartSimulation() {
83 pthread_create(&life_simulation_thread_, NULL, LifeSimulation, this);
84 }
85
86 Life::SimulationMode Life::WaitForRunMode() {
87 simulation_mode_.LockWhenNotCondition(kPaused);
88 simulation_mode_.Unlock();
89 return simulation_mode();
90 }
91
92 void Life::SetAutomatonRules(const std::string& rule_string) {
93 if (rule_string.size() == 0)
94 return;
95 // Separate the birth rule from the keep-alive rule.
96 size_t slash_pos = rule_string.find('/');
97 if (slash_pos == std::string::npos)
98 return;
99 std::string keep_alive_rule = rule_string.substr(0, slash_pos);
100 std::string birth_rule = rule_string.substr(slash_pos + 1);
101 threading::ScopedMutexLock scoped_mutex(&life_simulation_mutex_);
102 if (!scoped_mutex.is_valid())
103 return;
104 std::fill(&life_rules_table_[0],
105 &life_rules_table_[0] + life_rules_table_.size(),
106 0);
107 SetRuleFromString(kBirthRuleOffset, birth_rule);
108 SetRuleFromString(kKeepAliveRuleOffset, keep_alive_rule);
109 }
110
111 void Life::SetRuleFromString(size_t rule_offset,
112 const std::string& rule_string) {
113 for (size_t i = 0; i < rule_string.size(); ++i) {
114 size_t rule_index = rule_string[i] - '0';
115 life_rules_table_[rule_offset + rule_index] = 1;
116 }
117 }
118
119 void Life::Resize(int width, int height) {
120 DeleteCells();
121 width_ = std::max(width, 0);
122 height_ = std::max(height, 0);
123 size_t size = width * height;
124 cell_in_ = new uint8_t[size];
125 cell_out_ = new uint8_t[size];
126 ClearCells();
127 }
128
129 void Life::DeleteCells() {
130 delete[] cell_in_;
131 delete[] cell_out_;
132 cell_in_ = cell_out_ = NULL;
133 }
134
135 void Life::ClearCells() {
136 const size_t size = width() * height();
137 if (cell_in_)
138 std::fill(cell_in_, cell_in_ + size, 0);
139 if (cell_out_)
140 std::fill(cell_out_, cell_out_ + size, 0);
141 }
142
143 void Life::PutStampAtPoint(const Stamp& stamp, const pp::Point& point) {
144 // Note: do not acquire the pixel lock here, because stamping is done in the
145 // UI thread.
146 stamp.StampAtPointInBuffers(
147 point,
148 shared_pixel_buffer_->PixelBufferNoLock(),
149 cell_in_,
150 pp::Size(width(), height()));
151 }
152
153 void Life::AddRandomSeed() {
154 threading::ScopedMutexLock scoped_mutex(&life_simulation_mutex_);
155 if (!scoped_mutex.is_valid())
156 return;
157 if (cell_in_ == NULL || cell_out_ == NULL)
158 return;
159 const int sim_height = height();
160 const int sim_width = width();
161 for (int i = 0; i < sim_width; ++i) {
162 cell_in_[i] = random_bits_.value();
163 cell_in_[i + (sim_height - 1) * sim_width] = random_bits_.value();
164 }
165 for (int i = 0; i < sim_height; ++i) {
166 cell_in_[i * sim_width] = random_bits_.value();
167 cell_in_[i * sim_width + (sim_width - 1)] = random_bits_.value();
168 }
169 }
170
171 void Life::UpdateCells() {
172 ScopedPixelLock scoped_pixel_lock(shared_pixel_buffer_);
173 uint32_t* pixel_buffer = scoped_pixel_lock.pixels();
174 if (pixel_buffer == NULL || cell_in_ == NULL || cell_out_ == NULL) {
175 // Note that if the pixel buffer never gets initialized, this won't ever
176 // paint anything. Which is probably the right thing to do. Also, this
177 // clause means that the image will not get the very first few sim cells,
178 // since it's possible that this thread starts before the pixel buffer is
179 // initialized.
180 return;
181 }
182 const int sim_height = height();
183 const int sim_width = width();
184 // Do neighbor sumation; apply rules, output pixel color.
185 for (int y = 1; y < (sim_height - 1); ++y) {
186 uint8_t *src = cell_in_ + 1 + y * sim_width;
187 uint8_t *src_above = src - sim_width;
188 uint8_t *src_below = src + sim_width;
189 uint8_t *dst = cell_out_ + 1 + y * sim_width;
190 uint32_t *scanline = pixel_buffer + 1 + y * sim_width;
191 for (int x = 1; x < (sim_width - 1); ++x) {
192 // Build sum to get a neighbour count. By multiplying the current
193 // (center) cell by 9, this provides indices [0..8] that relate to the
194 // cases when the current cell is dead, and indices [9..17] that relate
195 // to the cases when the current cell is alive.
196 int count = *(src_above - 1) + *src_above + *(src_above + 1) +
197 *(src - 1) + *src * kKeepAliveRuleOffset + *(src + 1) +
198 *(src_below - 1) + *src_below + *(src_below + 1);
199 *dst++ = life_rules_table_[count];
200 *scanline++ = kNeighborColors[count];
201 ++src;
202 ++src_above;
203 ++src_below;
204 }
205 }
206 }
207
208 void Life::Swap() {
209 threading::ScopedMutexLock scoped_mutex(&life_simulation_mutex_);
210 if (!scoped_mutex.is_valid()) {
211 return;
212 }
213 if (cell_in_ == NULL || cell_out_ == NULL) {
214 return;
215 }
216 std::swap(cell_in_, cell_out_);
217 }
218
219 void* Life::LifeSimulation(void* param) {
220 Life* life = static_cast<Life*>(param);
221 // Run the Life simulation in an endless loop. Shut this down when
222 // is_simulation_running() returns |false|.
223 life->set_is_simulation_running(true);
224 while (life->is_simulation_running()) {
225 SimulationMode sim_mode = life->WaitForRunMode();
226 if (sim_mode == kRunRandomSeed) {
227 life->AddRandomSeed();
228 }
229 life->UpdateCells();
230 life->Swap();
231 }
232 return NULL;
233 }
234
235 uint8_t Life::RandomBitGenerator::value() {
236 return static_cast<uint8_t>(rand_r(&random_bit_seed_) & 1);
237 }
238
239 } // namespace life
240
OLDNEW
« no previous file with comments | « experimental/conways_life/life.h ('k') | experimental/conways_life/life.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698