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

Side by Side Diff: experimental/conways_life/life_application.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_application.h ('k') | experimental/conways_life/life_module.cc » ('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_application.h"
6
7 #include <algorithm>
8 #include <cassert>
9 #include <cmath>
10 #include <cstdio>
11 #include <cstring>
12 #include <sstream>
13 #include <string>
14
15 #include "experimental/conways_life/audio/web_wav_sound_resource.h"
16 #include "experimental/conways_life/scoped_pixel_lock.h"
17 #include "experimental/conways_life/threading/scoped_mutex_lock.h"
18 #include "ppapi/c/pp_errors.h"
19 #include "ppapi/cpp/completion_callback.h"
20 #include "ppapi/cpp/var.h"
21
22 namespace {
23 const char* const kClearMethodId = "clear";
24 const char* const kPutStampAtPointMethodId = "putStampAtPoint";
25 const char* const kRunSimulationMethodId = "runSimulation";
26 const char* const kSetAutomatonRulesMethodId = "setAutomatonRules";
27 const char* const kSetCurrentStampMethodId = "setCurrentStamp";
28 const char* const kSetStampSoundUrlMethodId = "setStampSoundUrl";
29 const char* const kStopSimulationMethodId = "stopSimulation";
30
31 const int kSimulationTickInterval = 10; // Measured in msec.
32 const uint32_t kBackgroundColor = 0xFFFFFFFF; // Opaque white.
33
34 // Simulation modes. These strings are matched by the browser script.
35 const char* const kRandomSeedModeId = "random_seed";
36 const char* const kStampModeId = "stamp";
37
38 // Return the value of parameter named |param_name| from |parameters|. If
39 // |param_name| doesn't exist, then return an empty string.
40 std::string GetParameterNamed(
41 const std::string& param_name,
42 const scripting::MethodParameter& parameters) {
43 scripting::MethodParameter::const_iterator i =
44 parameters.find(param_name);
45 if (i == parameters.end()) {
46 return "";
47 }
48 return i->second;
49 }
50
51 // Return the int32_t equivalent of |str|. All the usual C++ rounding rules
52 // apply.
53 int32_t StringAsInt32(const std::string& str) {
54 std::istringstream cvt_stream(str);
55 double double_val;
56 cvt_stream >> double_val;
57 return static_cast<int32_t>(double_val);
58 }
59
60 // Called from the browser when the delay time has elapsed. This routine
61 // runs a simulation update, then reschedules itself to run the next
62 // simulation tick.
63 void SimulationTickCallback(void* data, int32_t result) {
64 life::LifeApplication* life_app = static_cast<life::LifeApplication*>(data);
65 life_app->Update();
66 if (life_app->is_running()) {
67 pp::Module::Get()->core()->CallOnMainThread(
68 kSimulationTickInterval,
69 pp::CompletionCallback(&SimulationTickCallback, data),
70 PP_OK);
71 }
72 }
73
74 // Called from the browser when the 2D graphics have been flushed out to the
75 // device.
76 void FlushCallback(void* data, int32_t result) {
77 static_cast<life::LifeApplication*>(data)->set_flush_pending(false);
78 }
79 } // namespace
80
81 using scripting::ScriptingBridge;
82
83 namespace life {
84 LifeApplication::LifeApplication(PP_Instance instance)
85 : pp::Instance(instance),
86 graphics_2d_context_(NULL),
87 flush_pending_(false),
88 view_changed_size_(true),
89 audio_player_(this) {
90 }
91
92 LifeApplication::~LifeApplication() {
93 life_simulation_.set_is_simulation_running(false);
94 DestroyContext();
95 }
96
97 bool LifeApplication::Init(uint32_t /* argc */,
98 const char* /* argn */[],
99 const char* /* argv */[]) {
100 // Add all the methods to the scripting bridge.
101 ScriptingBridge::SharedMethodCallbackExecutor
102 clear_method(new scripting::MethodCallback<LifeApplication>(
103 this, &LifeApplication::Clear));
104 scripting_bridge_.AddMethodNamed(kClearMethodId, clear_method);
105
106 ScriptingBridge::SharedMethodCallbackExecutor
107 put_stamp_method(new scripting::MethodCallback<LifeApplication>(
108 this, &LifeApplication::PutStampAtPoint));
109 scripting_bridge_.AddMethodNamed(kPutStampAtPointMethodId, put_stamp_method);
110
111 ScriptingBridge::SharedMethodCallbackExecutor
112 run_sim_method(new scripting::MethodCallback<LifeApplication>(
113 this, &LifeApplication::RunSimulation));
114 scripting_bridge_.AddMethodNamed(kRunSimulationMethodId, run_sim_method);
115
116 ScriptingBridge::SharedMethodCallbackExecutor
117 set_auto_rules_method(new scripting::MethodCallback<LifeApplication>(
118 this, &LifeApplication::SetAutomatonRules));
119 scripting_bridge_.AddMethodNamed(kSetAutomatonRulesMethodId,
120 set_auto_rules_method);
121
122 ScriptingBridge::SharedMethodCallbackExecutor
123 set_stamp_method(new scripting::MethodCallback<LifeApplication>(
124 this, &LifeApplication::SetCurrentStamp));
125 scripting_bridge_.AddMethodNamed(kSetCurrentStampMethodId, set_stamp_method);
126
127 ScriptingBridge::SharedMethodCallbackExecutor
128 set_stamp_sound_method(new scripting::MethodCallback<LifeApplication>(
129 this, &LifeApplication::SetStampSoundUrl));
130 scripting_bridge_.AddMethodNamed(kSetStampSoundUrlMethodId,
131 set_stamp_sound_method);
132
133 ScriptingBridge::SharedMethodCallbackExecutor
134 stop_sim_method(new scripting::MethodCallback<LifeApplication>(
135 this, &LifeApplication::StopSimulation));
136 scripting_bridge_.AddMethodNamed(kStopSimulationMethodId, stop_sim_method);
137
138 life_simulation_.StartSimulation();
139 return true;
140 }
141
142 void LifeApplication::HandleMessage(const pp::Var& message) {
143 if (!message.is_string())
144 return;
145 scripting_bridge_.InvokeMethod(message.AsString());
146 }
147
148 void LifeApplication::DidChangeView(const pp::Rect& position,
149 const pp::Rect& /* clip */) {
150 if (position.size().width() == width() &&
151 position.size().height() == height())
152 return; // Size didn't change, no need to update anything.
153 // Indicate that all the buffers need to be resized at the next Update()
154 // call.
155 view_changed_size_ = true;
156 view_size_ = position.size();
157 // Make sure the buffers get changed if the simulation isn't running.
158 if (!is_running())
159 Update();
160 }
161
162 void LifeApplication::Update() {
163 if (flush_pending())
164 return; // Don't attempt to flush if one is pending.
165
166 if (view_changed_size_) {
167 // Delete the old pixel buffer and create a new one.
168 // Pause the simulation before changing all the buffer sizes.
169 Life::SimulationMode sim_mode = life_simulation_.simulation_mode();
170 life_simulation_.set_simulation_mode(Life::kPaused);
171 // Create a new device context with the new size.
172 // Note: DestroyContext() releases the simulation's copy of the shared
173 // pixel buffer. *This has to happen before the reset() below!* If the
174 // simulation's copy of hte shared pointer is released last, then the
175 // underlying ImageData is released off the main thread, which is not
176 // supported in Pepper.
177 DestroyContext();
178 CreateContext(view_size_);
179 threading::ScopedMutexLock scoped_mutex(
180 life_simulation_.simulation_mutex());
181 if (!scoped_mutex.is_valid())
182 // This potentially leaves the simulation in a paused state, but getting
183 // here means something is very wrong and the simulation probably can't
184 // run anyways.
185 return;
186 life_simulation_.DeleteCells();
187 if (graphics_2d_context_ != NULL) {
188 shared_pixel_buffer_.reset(
189 new LockingImageData(this,
190 PP_IMAGEDATAFORMAT_BGRA_PREMUL,
191 graphics_2d_context_->size(),
192 false));
193 set_flush_pending(false);
194 // Ok to get a non-locked version because the simulation is guraranteed
195 // to be paused here.
196 uint32_t* pixels = shared_pixel_buffer_->PixelBufferNoLock();
197 if (pixels) {
198 const size_t size = width() * height();
199 std::fill(pixels, pixels + size, kBackgroundColor);
200 }
201 life_simulation_.Resize(width(), height());
202 life_simulation_.set_pixel_buffer(shared_pixel_buffer_);
203 life_simulation_.set_simulation_mode(sim_mode);
204 }
205 view_changed_size_ = false;
206 }
207 FlushPixelBuffer();
208 }
209
210 void LifeApplication::SetCurrentStamp(
211 const scripting::ScriptingBridge& bridge,
212 const scripting::MethodParameter& parameters) {
213 std::string stamp_desc = GetParameterNamed("description", parameters);
214 if (stamp_desc.length()) {
215 stamp_.InitFromDescription(stamp_desc);
216 }
217 }
218
219 void LifeApplication::Clear(
220 const scripting::ScriptingBridge& bridge,
221 const scripting::MethodParameter& parameters) {
222 // Temporarily pause the the simulation while clearing the buffers.
223 volatile Life::SimulationMode sim_mode = life_simulation_.simulation_mode();
224 if (sim_mode != Life::kPaused)
225 life_simulation_.set_simulation_mode(Life::kPaused);
226 life_simulation_.ClearCells();
227 ScopedPixelLock scoped_pixel_lock(shared_pixel_buffer_);
228 uint32_t* pixel_buffer = scoped_pixel_lock.pixels();
229 if (pixel_buffer) {
230 const size_t size = width() * height();
231 std::fill(pixel_buffer,
232 pixel_buffer + size,
233 kBackgroundColor);
234 }
235 Update(); // Flushes the buffer correctly.
236 if (sim_mode != Life::kPaused)
237 life_simulation_.set_simulation_mode(sim_mode);
238 }
239
240 void LifeApplication::SetAutomatonRules(
241 const scripting::ScriptingBridge& bridge,
242 const scripting::MethodParameter& parameters) {
243 std::string rules = GetParameterNamed("rules", parameters);
244 if (rules.length()) {
245 life_simulation_.SetAutomatonRules(rules);
246 }
247 }
248
249 void LifeApplication::RunSimulation(
250 const scripting::ScriptingBridge& bridge,
251 const scripting::MethodParameter& parameters) {
252 std::string sim_mode = GetParameterNamed("mode", parameters);
253 if (sim_mode.length() == 0) {
254 return;
255 }
256 if (sim_mode == kRandomSeedModeId) {
257 life_simulation_.set_simulation_mode(life::Life::kRunRandomSeed);
258 } else {
259 life_simulation_.set_simulation_mode(life::Life::kRunStamp);
260 }
261 // Schedule a simulation tick to get things going.
262 pp::Module::Get()->core()->CallOnMainThread(
263 kSimulationTickInterval,
264 pp::CompletionCallback(&SimulationTickCallback, this),
265 PP_OK);
266 }
267
268 void LifeApplication::StopSimulation(
269 const scripting::ScriptingBridge& bridge,
270 const scripting::MethodParameter& parameters) {
271 // This will pause the simulation on the next tick.
272 life_simulation_.set_simulation_mode(life::Life::kPaused);
273 }
274
275 void LifeApplication::PutStampAtPoint(
276 const scripting::ScriptingBridge& bridge,
277 const scripting::MethodParameter& parameters) {
278 std::string x_coord = GetParameterNamed("x", parameters);
279 std::string y_coord = GetParameterNamed("y", parameters);
280 if (x_coord.length() == 0 || y_coord.length() == 0) {
281 return;
282 }
283 int32_t x = StringAsInt32(x_coord);
284 int32_t y = StringAsInt32(y_coord);
285 life_simulation_.PutStampAtPoint(stamp_, pp::Point(x, y));
286 // Play the stamp sound.
287 if (audio_player_.IsReady())
288 audio_player_.Play();
289 // If the simulation isn't running, make sure the stamp shows up.
290 if (!is_running())
291 Update();
292 }
293
294 void LifeApplication::SetStampSoundUrl(
295 const scripting::ScriptingBridge& bridge,
296 const scripting::MethodParameter& parameters) {
297 std::string sound_url = GetParameterNamed("soundUrl", parameters);
298 if (sound_url.length() == 0) {
299 return;
300 }
301 audio::WebWavSoundResource* sound = new audio::WebWavSoundResource();
302 sound->Init(sound_url, this);
303 // |audio_player_| takes ownership of |sound| and is responsible for
304 // deleting it.
305 audio_player_.AssignAudioSource(sound);
306 }
307
308 void LifeApplication::CreateContext(const pp::Size& size) {
309 if (IsContextValid())
310 return;
311 graphics_2d_context_ = new pp::Graphics2D(this, size, false);
312 if (!BindGraphics(*graphics_2d_context_)) {
313 printf("Couldn't bind the device context\n");
314 }
315 }
316
317 void LifeApplication::DestroyContext() {
318 threading::ScopedMutexLock scoped_mutex(life_simulation_.simulation_mutex());
319 if (!scoped_mutex.is_valid()) {
320 return;
321 }
322 ScopedPixelLock scoped_pixel_lock(shared_pixel_buffer_);
323 shared_pixel_buffer_.reset();
324 life_simulation_.set_pixel_buffer(shared_pixel_buffer_);
325 if (!IsContextValid())
326 return;
327 delete graphics_2d_context_;
328 graphics_2d_context_ = NULL;
329 }
330
331 void LifeApplication::FlushPixelBuffer() {
332 if (!IsContextValid() || shared_pixel_buffer_ == NULL)
333 return;
334 set_flush_pending(true);
335 graphics_2d_context_->PaintImageData(*shared_pixel_buffer_, pp::Point());
336 graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
337 }
338 } // namespace life
339
OLDNEW
« no previous file with comments | « experimental/conways_life/life_application.h ('k') | experimental/conways_life/life_module.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698