| Index: experimental/conways_life/life.cc
|
| diff --git a/experimental/conways_life/life.cc b/experimental/conways_life/life.cc
|
| deleted file mode 100644
|
| index ca1aedeafb15ae8ea78513bed5ee46114627145f..0000000000000000000000000000000000000000
|
| --- a/experimental/conways_life/life.cc
|
| +++ /dev/null
|
| @@ -1,240 +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.h"
|
| -
|
| -#include <stdio.h>
|
| -#include <algorithm>
|
| -#include <cmath>
|
| -#include <string>
|
| -
|
| -#include "experimental/conways_life/scoped_pixel_lock.h"
|
| -#include "experimental/conways_life/threading/scoped_mutex_lock.h"
|
| -#include "ppapi/cpp/size.h"
|
| -
|
| -namespace {
|
| -const unsigned int kInitialRandSeed = 0xC0DE533D;
|
| -const int kMaxNeighbourCount = 8;
|
| -// Offests into the autmaton rule lookup table.
|
| -const size_t kKeepAliveRuleOffset = 9;
|
| -const size_t kBirthRuleOffset = 0;
|
| -
|
| -inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
|
| - return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
|
| -}
|
| -
|
| -// Map of neighboring colors.
|
| -const uint32_t kNeighborColors[] = {
|
| - MakeRGBA(0xFF, 0xFF, 0xFF, 0xFF), // Dead with 0 neighbours.
|
| - MakeRGBA(0xE0, 0xE0, 0xE0, 0xFF), // Dead with 1 neighbour.
|
| - MakeRGBA(0xC0, 0xC0, 0xC0, 0xFF), // 2 neighbours.
|
| - MakeRGBA(0xA0, 0xA0, 0xA0, 0xFF), // 3
|
| - MakeRGBA(0x80, 0x80, 0x80, 0xFF), // 4
|
| - MakeRGBA(0x60, 0x60, 0x60, 0xFF), // 5
|
| - MakeRGBA(0x40, 0x40, 0x40, 0xFF), // 6
|
| - MakeRGBA(0x20, 0x20, 0x20, 0xFF), // 7
|
| - MakeRGBA(0x10, 0x10, 0x10, 0xFF), // 8
|
| - MakeRGBA(0x00, 0x00, 0x00, 0xFF), // Alive with 0 neighbours.
|
| - MakeRGBA(0x10, 0x10, 0x10, 0xFF), // Alive with 1 neighbours.
|
| - MakeRGBA(0x20, 0x20, 0x20, 0xFF), // 2 neighbours.
|
| - MakeRGBA(0x30, 0x30, 0x30, 0xFF), // 3
|
| - MakeRGBA(0x40, 0x40, 0x40, 0xFF), // 4
|
| - MakeRGBA(0x60, 0x60, 0x60, 0xFF), // 5
|
| - MakeRGBA(0x80, 0x80, 0x80, 0xFF), // 6
|
| - MakeRGBA(0xC0, 0xC0, 0xC0, 0xFF), // 7
|
| - MakeRGBA(0xF0, 0xF0, 0xF0, 0xFF) // 8
|
| -};
|
| -} // namespace
|
| -
|
| -namespace life {
|
| -Life::Life() : life_simulation_thread_(NULL),
|
| - sim_state_condition_(kSimulationStopped),
|
| - width_(0),
|
| - height_(0),
|
| - simulation_mode_(kPaused),
|
| - random_bits_(kInitialRandSeed),
|
| - cell_in_(NULL),
|
| - cell_out_(NULL) {
|
| - pthread_mutex_init(&life_simulation_mutex_, NULL);
|
| - // Set up the default life rules table. |life_rules_table_| is a look-up
|
| - // table, index by the number of living neighbours of a cell. Indices [0..8]
|
| - // represent the rules when the cell being examined is dead; indices [9..17]
|
| - // represnt the rules when the cell is alive.
|
| - life_rules_table_.resize(kMaxNeighbourCount * 2 + 1);
|
| - std::fill(&life_rules_table_[0],
|
| - &life_rules_table_[0] + life_rules_table_.size(),
|
| - 0);
|
| - life_rules_table_[kBirthRuleOffset + 3] = 1;
|
| - life_rules_table_[kKeepAliveRuleOffset + 2] = 1;
|
| - life_rules_table_[kKeepAliveRuleOffset + 3] = 1;
|
| -}
|
| -
|
| -Life::~Life() {
|
| - set_is_simulation_running(false);
|
| - if (life_simulation_thread_) {
|
| - pthread_join(life_simulation_thread_, NULL);
|
| - }
|
| - DeleteCells();
|
| - pthread_mutex_destroy(&life_simulation_mutex_);
|
| -}
|
| -
|
| -void Life::StartSimulation() {
|
| - pthread_create(&life_simulation_thread_, NULL, LifeSimulation, this);
|
| -}
|
| -
|
| -Life::SimulationMode Life::WaitForRunMode() {
|
| - simulation_mode_.LockWhenNotCondition(kPaused);
|
| - simulation_mode_.Unlock();
|
| - return simulation_mode();
|
| -}
|
| -
|
| -void Life::SetAutomatonRules(const std::string& rule_string) {
|
| - if (rule_string.size() == 0)
|
| - return;
|
| - // Separate the birth rule from the keep-alive rule.
|
| - size_t slash_pos = rule_string.find('/');
|
| - if (slash_pos == std::string::npos)
|
| - return;
|
| - std::string keep_alive_rule = rule_string.substr(0, slash_pos);
|
| - std::string birth_rule = rule_string.substr(slash_pos + 1);
|
| - threading::ScopedMutexLock scoped_mutex(&life_simulation_mutex_);
|
| - if (!scoped_mutex.is_valid())
|
| - return;
|
| - std::fill(&life_rules_table_[0],
|
| - &life_rules_table_[0] + life_rules_table_.size(),
|
| - 0);
|
| - SetRuleFromString(kBirthRuleOffset, birth_rule);
|
| - SetRuleFromString(kKeepAliveRuleOffset, keep_alive_rule);
|
| -}
|
| -
|
| -void Life::SetRuleFromString(size_t rule_offset,
|
| - const std::string& rule_string) {
|
| - for (size_t i = 0; i < rule_string.size(); ++i) {
|
| - size_t rule_index = rule_string[i] - '0';
|
| - life_rules_table_[rule_offset + rule_index] = 1;
|
| - }
|
| -}
|
| -
|
| -void Life::Resize(int width, int height) {
|
| - DeleteCells();
|
| - width_ = std::max(width, 0);
|
| - height_ = std::max(height, 0);
|
| - size_t size = width * height;
|
| - cell_in_ = new uint8_t[size];
|
| - cell_out_ = new uint8_t[size];
|
| - ClearCells();
|
| -}
|
| -
|
| -void Life::DeleteCells() {
|
| - delete[] cell_in_;
|
| - delete[] cell_out_;
|
| - cell_in_ = cell_out_ = NULL;
|
| -}
|
| -
|
| -void Life::ClearCells() {
|
| - const size_t size = width() * height();
|
| - if (cell_in_)
|
| - std::fill(cell_in_, cell_in_ + size, 0);
|
| - if (cell_out_)
|
| - std::fill(cell_out_, cell_out_ + size, 0);
|
| -}
|
| -
|
| -void Life::PutStampAtPoint(const Stamp& stamp, const pp::Point& point) {
|
| - // Note: do not acquire the pixel lock here, because stamping is done in the
|
| - // UI thread.
|
| - stamp.StampAtPointInBuffers(
|
| - point,
|
| - shared_pixel_buffer_->PixelBufferNoLock(),
|
| - cell_in_,
|
| - pp::Size(width(), height()));
|
| -}
|
| -
|
| -void Life::AddRandomSeed() {
|
| - threading::ScopedMutexLock scoped_mutex(&life_simulation_mutex_);
|
| - if (!scoped_mutex.is_valid())
|
| - return;
|
| - if (cell_in_ == NULL || cell_out_ == NULL)
|
| - return;
|
| - const int sim_height = height();
|
| - const int sim_width = width();
|
| - for (int i = 0; i < sim_width; ++i) {
|
| - cell_in_[i] = random_bits_.value();
|
| - cell_in_[i + (sim_height - 1) * sim_width] = random_bits_.value();
|
| - }
|
| - for (int i = 0; i < sim_height; ++i) {
|
| - cell_in_[i * sim_width] = random_bits_.value();
|
| - cell_in_[i * sim_width + (sim_width - 1)] = random_bits_.value();
|
| - }
|
| -}
|
| -
|
| -void Life::UpdateCells() {
|
| - ScopedPixelLock scoped_pixel_lock(shared_pixel_buffer_);
|
| - uint32_t* pixel_buffer = scoped_pixel_lock.pixels();
|
| - if (pixel_buffer == NULL || cell_in_ == NULL || cell_out_ == NULL) {
|
| - // Note that if the pixel buffer never gets initialized, this won't ever
|
| - // paint anything. Which is probably the right thing to do. Also, this
|
| - // clause means that the image will not get the very first few sim cells,
|
| - // since it's possible that this thread starts before the pixel buffer is
|
| - // initialized.
|
| - return;
|
| - }
|
| - const int sim_height = height();
|
| - const int sim_width = width();
|
| - // Do neighbor sumation; apply rules, output pixel color.
|
| - for (int y = 1; y < (sim_height - 1); ++y) {
|
| - uint8_t *src = cell_in_ + 1 + y * sim_width;
|
| - uint8_t *src_above = src - sim_width;
|
| - uint8_t *src_below = src + sim_width;
|
| - uint8_t *dst = cell_out_ + 1 + y * sim_width;
|
| - uint32_t *scanline = pixel_buffer + 1 + y * sim_width;
|
| - for (int x = 1; x < (sim_width - 1); ++x) {
|
| - // Build sum to get a neighbour count. By multiplying the current
|
| - // (center) cell by 9, this provides indices [0..8] that relate to the
|
| - // cases when the current cell is dead, and indices [9..17] that relate
|
| - // to the cases when the current cell is alive.
|
| - int count = *(src_above - 1) + *src_above + *(src_above + 1) +
|
| - *(src - 1) + *src * kKeepAliveRuleOffset + *(src + 1) +
|
| - *(src_below - 1) + *src_below + *(src_below + 1);
|
| - *dst++ = life_rules_table_[count];
|
| - *scanline++ = kNeighborColors[count];
|
| - ++src;
|
| - ++src_above;
|
| - ++src_below;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void Life::Swap() {
|
| - threading::ScopedMutexLock scoped_mutex(&life_simulation_mutex_);
|
| - if (!scoped_mutex.is_valid()) {
|
| - return;
|
| - }
|
| - if (cell_in_ == NULL || cell_out_ == NULL) {
|
| - return;
|
| - }
|
| - std::swap(cell_in_, cell_out_);
|
| -}
|
| -
|
| -void* Life::LifeSimulation(void* param) {
|
| - Life* life = static_cast<Life*>(param);
|
| - // Run the Life simulation in an endless loop. Shut this down when
|
| - // is_simulation_running() returns |false|.
|
| - life->set_is_simulation_running(true);
|
| - while (life->is_simulation_running()) {
|
| - SimulationMode sim_mode = life->WaitForRunMode();
|
| - if (sim_mode == kRunRandomSeed) {
|
| - life->AddRandomSeed();
|
| - }
|
| - life->UpdateCells();
|
| - life->Swap();
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -uint8_t Life::RandomBitGenerator::value() {
|
| - return static_cast<uint8_t>(rand_r(&random_bit_seed_) & 1);
|
| -}
|
| -
|
| -} // namespace life
|
| -
|
|
|