| Index: experimental/conways_life/life_application.cc
|
| diff --git a/experimental/conways_life/life_application.cc b/experimental/conways_life/life_application.cc
|
| deleted file mode 100644
|
| index 307026589a20667173a81f8e948c62ff619f778e..0000000000000000000000000000000000000000
|
| --- a/experimental/conways_life/life_application.cc
|
| +++ /dev/null
|
| @@ -1,339 +0,0 @@
|
| -// Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "experimental/conways_life/life_application.h"
|
| -
|
| -#include <algorithm>
|
| -#include <cassert>
|
| -#include <cmath>
|
| -#include <cstdio>
|
| -#include <cstring>
|
| -#include <sstream>
|
| -#include <string>
|
| -
|
| -#include "experimental/conways_life/audio/web_wav_sound_resource.h"
|
| -#include "experimental/conways_life/scoped_pixel_lock.h"
|
| -#include "experimental/conways_life/threading/scoped_mutex_lock.h"
|
| -#include "ppapi/c/pp_errors.h"
|
| -#include "ppapi/cpp/completion_callback.h"
|
| -#include "ppapi/cpp/var.h"
|
| -
|
| -namespace {
|
| -const char* const kClearMethodId = "clear";
|
| -const char* const kPutStampAtPointMethodId = "putStampAtPoint";
|
| -const char* const kRunSimulationMethodId = "runSimulation";
|
| -const char* const kSetAutomatonRulesMethodId = "setAutomatonRules";
|
| -const char* const kSetCurrentStampMethodId = "setCurrentStamp";
|
| -const char* const kSetStampSoundUrlMethodId = "setStampSoundUrl";
|
| -const char* const kStopSimulationMethodId = "stopSimulation";
|
| -
|
| -const int kSimulationTickInterval = 10; // Measured in msec.
|
| -const uint32_t kBackgroundColor = 0xFFFFFFFF; // Opaque white.
|
| -
|
| -// Simulation modes. These strings are matched by the browser script.
|
| -const char* const kRandomSeedModeId = "random_seed";
|
| -const char* const kStampModeId = "stamp";
|
| -
|
| -// Return the value of parameter named |param_name| from |parameters|. If
|
| -// |param_name| doesn't exist, then return an empty string.
|
| -std::string GetParameterNamed(
|
| - const std::string& param_name,
|
| - const scripting::MethodParameter& parameters) {
|
| - scripting::MethodParameter::const_iterator i =
|
| - parameters.find(param_name);
|
| - if (i == parameters.end()) {
|
| - return "";
|
| - }
|
| - return i->second;
|
| -}
|
| -
|
| -// Return the int32_t equivalent of |str|. All the usual C++ rounding rules
|
| -// apply.
|
| -int32_t StringAsInt32(const std::string& str) {
|
| - std::istringstream cvt_stream(str);
|
| - double double_val;
|
| - cvt_stream >> double_val;
|
| - return static_cast<int32_t>(double_val);
|
| -}
|
| -
|
| -// Called from the browser when the delay time has elapsed. This routine
|
| -// runs a simulation update, then reschedules itself to run the next
|
| -// simulation tick.
|
| -void SimulationTickCallback(void* data, int32_t result) {
|
| - life::LifeApplication* life_app = static_cast<life::LifeApplication*>(data);
|
| - life_app->Update();
|
| - if (life_app->is_running()) {
|
| - pp::Module::Get()->core()->CallOnMainThread(
|
| - kSimulationTickInterval,
|
| - pp::CompletionCallback(&SimulationTickCallback, data),
|
| - PP_OK);
|
| - }
|
| -}
|
| -
|
| -// Called from the browser when the 2D graphics have been flushed out to the
|
| -// device.
|
| -void FlushCallback(void* data, int32_t result) {
|
| - static_cast<life::LifeApplication*>(data)->set_flush_pending(false);
|
| -}
|
| -} // namespace
|
| -
|
| -using scripting::ScriptingBridge;
|
| -
|
| -namespace life {
|
| -LifeApplication::LifeApplication(PP_Instance instance)
|
| - : pp::Instance(instance),
|
| - graphics_2d_context_(NULL),
|
| - flush_pending_(false),
|
| - view_changed_size_(true),
|
| - audio_player_(this) {
|
| -}
|
| -
|
| -LifeApplication::~LifeApplication() {
|
| - life_simulation_.set_is_simulation_running(false);
|
| - DestroyContext();
|
| -}
|
| -
|
| -bool LifeApplication::Init(uint32_t /* argc */,
|
| - const char* /* argn */[],
|
| - const char* /* argv */[]) {
|
| - // Add all the methods to the scripting bridge.
|
| - ScriptingBridge::SharedMethodCallbackExecutor
|
| - clear_method(new scripting::MethodCallback<LifeApplication>(
|
| - this, &LifeApplication::Clear));
|
| - scripting_bridge_.AddMethodNamed(kClearMethodId, clear_method);
|
| -
|
| - ScriptingBridge::SharedMethodCallbackExecutor
|
| - put_stamp_method(new scripting::MethodCallback<LifeApplication>(
|
| - this, &LifeApplication::PutStampAtPoint));
|
| - scripting_bridge_.AddMethodNamed(kPutStampAtPointMethodId, put_stamp_method);
|
| -
|
| - ScriptingBridge::SharedMethodCallbackExecutor
|
| - run_sim_method(new scripting::MethodCallback<LifeApplication>(
|
| - this, &LifeApplication::RunSimulation));
|
| - scripting_bridge_.AddMethodNamed(kRunSimulationMethodId, run_sim_method);
|
| -
|
| - ScriptingBridge::SharedMethodCallbackExecutor
|
| - set_auto_rules_method(new scripting::MethodCallback<LifeApplication>(
|
| - this, &LifeApplication::SetAutomatonRules));
|
| - scripting_bridge_.AddMethodNamed(kSetAutomatonRulesMethodId,
|
| - set_auto_rules_method);
|
| -
|
| - ScriptingBridge::SharedMethodCallbackExecutor
|
| - set_stamp_method(new scripting::MethodCallback<LifeApplication>(
|
| - this, &LifeApplication::SetCurrentStamp));
|
| - scripting_bridge_.AddMethodNamed(kSetCurrentStampMethodId, set_stamp_method);
|
| -
|
| - ScriptingBridge::SharedMethodCallbackExecutor
|
| - set_stamp_sound_method(new scripting::MethodCallback<LifeApplication>(
|
| - this, &LifeApplication::SetStampSoundUrl));
|
| - scripting_bridge_.AddMethodNamed(kSetStampSoundUrlMethodId,
|
| - set_stamp_sound_method);
|
| -
|
| - ScriptingBridge::SharedMethodCallbackExecutor
|
| - stop_sim_method(new scripting::MethodCallback<LifeApplication>(
|
| - this, &LifeApplication::StopSimulation));
|
| - scripting_bridge_.AddMethodNamed(kStopSimulationMethodId, stop_sim_method);
|
| -
|
| - life_simulation_.StartSimulation();
|
| - return true;
|
| -}
|
| -
|
| -void LifeApplication::HandleMessage(const pp::Var& message) {
|
| - if (!message.is_string())
|
| - return;
|
| - scripting_bridge_.InvokeMethod(message.AsString());
|
| -}
|
| -
|
| -void LifeApplication::DidChangeView(const pp::Rect& position,
|
| - const pp::Rect& /* clip */) {
|
| - if (position.size().width() == width() &&
|
| - position.size().height() == height())
|
| - return; // Size didn't change, no need to update anything.
|
| - // Indicate that all the buffers need to be resized at the next Update()
|
| - // call.
|
| - view_changed_size_ = true;
|
| - view_size_ = position.size();
|
| - // Make sure the buffers get changed if the simulation isn't running.
|
| - if (!is_running())
|
| - Update();
|
| -}
|
| -
|
| -void LifeApplication::Update() {
|
| - if (flush_pending())
|
| - return; // Don't attempt to flush if one is pending.
|
| -
|
| - if (view_changed_size_) {
|
| - // Delete the old pixel buffer and create a new one.
|
| - // Pause the simulation before changing all the buffer sizes.
|
| - Life::SimulationMode sim_mode = life_simulation_.simulation_mode();
|
| - life_simulation_.set_simulation_mode(Life::kPaused);
|
| - // Create a new device context with the new size.
|
| - // Note: DestroyContext() releases the simulation's copy of the shared
|
| - // pixel buffer. *This has to happen before the reset() below!* If the
|
| - // simulation's copy of hte shared pointer is released last, then the
|
| - // underlying ImageData is released off the main thread, which is not
|
| - // supported in Pepper.
|
| - DestroyContext();
|
| - CreateContext(view_size_);
|
| - threading::ScopedMutexLock scoped_mutex(
|
| - life_simulation_.simulation_mutex());
|
| - if (!scoped_mutex.is_valid())
|
| - // This potentially leaves the simulation in a paused state, but getting
|
| - // here means something is very wrong and the simulation probably can't
|
| - // run anyways.
|
| - return;
|
| - life_simulation_.DeleteCells();
|
| - if (graphics_2d_context_ != NULL) {
|
| - shared_pixel_buffer_.reset(
|
| - new LockingImageData(this,
|
| - PP_IMAGEDATAFORMAT_BGRA_PREMUL,
|
| - graphics_2d_context_->size(),
|
| - false));
|
| - set_flush_pending(false);
|
| - // Ok to get a non-locked version because the simulation is guraranteed
|
| - // to be paused here.
|
| - uint32_t* pixels = shared_pixel_buffer_->PixelBufferNoLock();
|
| - if (pixels) {
|
| - const size_t size = width() * height();
|
| - std::fill(pixels, pixels + size, kBackgroundColor);
|
| - }
|
| - life_simulation_.Resize(width(), height());
|
| - life_simulation_.set_pixel_buffer(shared_pixel_buffer_);
|
| - life_simulation_.set_simulation_mode(sim_mode);
|
| - }
|
| - view_changed_size_ = false;
|
| - }
|
| - FlushPixelBuffer();
|
| -}
|
| -
|
| -void LifeApplication::SetCurrentStamp(
|
| - const scripting::ScriptingBridge& bridge,
|
| - const scripting::MethodParameter& parameters) {
|
| - std::string stamp_desc = GetParameterNamed("description", parameters);
|
| - if (stamp_desc.length()) {
|
| - stamp_.InitFromDescription(stamp_desc);
|
| - }
|
| -}
|
| -
|
| -void LifeApplication::Clear(
|
| - const scripting::ScriptingBridge& bridge,
|
| - const scripting::MethodParameter& parameters) {
|
| - // Temporarily pause the the simulation while clearing the buffers.
|
| - volatile Life::SimulationMode sim_mode = life_simulation_.simulation_mode();
|
| - if (sim_mode != Life::kPaused)
|
| - life_simulation_.set_simulation_mode(Life::kPaused);
|
| - life_simulation_.ClearCells();
|
| - ScopedPixelLock scoped_pixel_lock(shared_pixel_buffer_);
|
| - uint32_t* pixel_buffer = scoped_pixel_lock.pixels();
|
| - if (pixel_buffer) {
|
| - const size_t size = width() * height();
|
| - std::fill(pixel_buffer,
|
| - pixel_buffer + size,
|
| - kBackgroundColor);
|
| - }
|
| - Update(); // Flushes the buffer correctly.
|
| - if (sim_mode != Life::kPaused)
|
| - life_simulation_.set_simulation_mode(sim_mode);
|
| -}
|
| -
|
| -void LifeApplication::SetAutomatonRules(
|
| - const scripting::ScriptingBridge& bridge,
|
| - const scripting::MethodParameter& parameters) {
|
| - std::string rules = GetParameterNamed("rules", parameters);
|
| - if (rules.length()) {
|
| - life_simulation_.SetAutomatonRules(rules);
|
| - }
|
| -}
|
| -
|
| -void LifeApplication::RunSimulation(
|
| - const scripting::ScriptingBridge& bridge,
|
| - const scripting::MethodParameter& parameters) {
|
| - std::string sim_mode = GetParameterNamed("mode", parameters);
|
| - if (sim_mode.length() == 0) {
|
| - return;
|
| - }
|
| - if (sim_mode == kRandomSeedModeId) {
|
| - life_simulation_.set_simulation_mode(life::Life::kRunRandomSeed);
|
| - } else {
|
| - life_simulation_.set_simulation_mode(life::Life::kRunStamp);
|
| - }
|
| - // Schedule a simulation tick to get things going.
|
| - pp::Module::Get()->core()->CallOnMainThread(
|
| - kSimulationTickInterval,
|
| - pp::CompletionCallback(&SimulationTickCallback, this),
|
| - PP_OK);
|
| -}
|
| -
|
| -void LifeApplication::StopSimulation(
|
| - const scripting::ScriptingBridge& bridge,
|
| - const scripting::MethodParameter& parameters) {
|
| - // This will pause the simulation on the next tick.
|
| - life_simulation_.set_simulation_mode(life::Life::kPaused);
|
| -}
|
| -
|
| -void LifeApplication::PutStampAtPoint(
|
| - const scripting::ScriptingBridge& bridge,
|
| - const scripting::MethodParameter& parameters) {
|
| - std::string x_coord = GetParameterNamed("x", parameters);
|
| - std::string y_coord = GetParameterNamed("y", parameters);
|
| - if (x_coord.length() == 0 || y_coord.length() == 0) {
|
| - return;
|
| - }
|
| - int32_t x = StringAsInt32(x_coord);
|
| - int32_t y = StringAsInt32(y_coord);
|
| - life_simulation_.PutStampAtPoint(stamp_, pp::Point(x, y));
|
| - // Play the stamp sound.
|
| - if (audio_player_.IsReady())
|
| - audio_player_.Play();
|
| - // If the simulation isn't running, make sure the stamp shows up.
|
| - if (!is_running())
|
| - Update();
|
| -}
|
| -
|
| -void LifeApplication::SetStampSoundUrl(
|
| - const scripting::ScriptingBridge& bridge,
|
| - const scripting::MethodParameter& parameters) {
|
| - std::string sound_url = GetParameterNamed("soundUrl", parameters);
|
| - if (sound_url.length() == 0) {
|
| - return;
|
| - }
|
| - audio::WebWavSoundResource* sound = new audio::WebWavSoundResource();
|
| - sound->Init(sound_url, this);
|
| - // |audio_player_| takes ownership of |sound| and is responsible for
|
| - // deleting it.
|
| - audio_player_.AssignAudioSource(sound);
|
| -}
|
| -
|
| -void LifeApplication::CreateContext(const pp::Size& size) {
|
| - if (IsContextValid())
|
| - return;
|
| - graphics_2d_context_ = new pp::Graphics2D(this, size, false);
|
| - if (!BindGraphics(*graphics_2d_context_)) {
|
| - printf("Couldn't bind the device context\n");
|
| - }
|
| -}
|
| -
|
| -void LifeApplication::DestroyContext() {
|
| - threading::ScopedMutexLock scoped_mutex(life_simulation_.simulation_mutex());
|
| - if (!scoped_mutex.is_valid()) {
|
| - return;
|
| - }
|
| - ScopedPixelLock scoped_pixel_lock(shared_pixel_buffer_);
|
| - shared_pixel_buffer_.reset();
|
| - life_simulation_.set_pixel_buffer(shared_pixel_buffer_);
|
| - if (!IsContextValid())
|
| - return;
|
| - delete graphics_2d_context_;
|
| - graphics_2d_context_ = NULL;
|
| -}
|
| -
|
| -void LifeApplication::FlushPixelBuffer() {
|
| - if (!IsContextValid() || shared_pixel_buffer_ == NULL)
|
| - return;
|
| - set_flush_pending(true);
|
| - graphics_2d_context_->PaintImageData(*shared_pixel_buffer_, pp::Point());
|
| - graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
|
| -}
|
| -} // namespace life
|
| -
|
|
|