<commit_before>// Copyright 2014 The Chromium 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 "media/midi/midi_manager.h"

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

namespace {

class FakeMidiManager : public MidiManager {
 public:
  FakeMidiManager() : start_initialization_is_called_(false) {}
  virtual ~FakeMidiManager() {}

  // MidiManager implementation.
  virtual void StartInitialization() OVERRIDE {
    start_initialization_is_called_ = true;
  }

  virtual void DispatchSendMidiData(MidiManagerClient* client,
                                    uint32 port_index,
                                    const std::vector<uint8>& data,
                                    double timestamp) OVERRIDE {}

  // Utility functions for testing.
  void CallCompleteInitialization(MidiResult result) {
    CompleteInitialization(result);
  }

  size_t GetClientCount() const {
    return get_clients_size_for_testing();
  }

  size_t GetPendingClientCount() const {
    return get_pending_clients_size_for_testing();
  }

  bool start_initialization_is_called_;

 private:
  DISALLOW_COPY_AND_ASSIGN(FakeMidiManager);
};

class FakeMidiManagerClient : public MidiManagerClient {
 public:
  explicit FakeMidiManagerClient(int client_id)
      : client_id_(client_id),
        result_(MIDI_NOT_SUPPORTED),
        wait_for_result_(true) {}
  virtual ~FakeMidiManagerClient() {}

  // MidiManagerClient implementation.
  virtual void CompleteStartSession(int client_id, MidiResult result) OVERRIDE {
    CHECK_EQ(client_id_, client_id);
    result_ = result;
    wait_for_result_ = false;
  }

  virtual void ReceiveMidiData(uint32 port_index, const uint8* data,
                               size_t size, double timestamp) OVERRIDE {}
  virtual void AccumulateMidiBytesSent(size_t size) OVERRIDE {}

  int get_client_id() const { return client_id_; }
  MidiResult get_result() const { return result_; }

  MidiResult WaitForResult() {
    base::RunLoop run_loop;
    // CompleteStartSession() is called inside the message loop on the same
    // thread. Protection for |wait_for_result_| is not needed.
    while (wait_for_result_)
      run_loop.RunUntilIdle();
    return get_result();
  }

 private:
  int client_id_;
  MidiResult result_;
  bool wait_for_result_;

  DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
};

class MidiManagerTest : public ::testing::Test {
 public:
  MidiManagerTest()
      : message_loop_(new base::MessageLoop), manager_(new FakeMidiManager) {}
  virtual ~MidiManagerTest() {}

 protected:
  void StartTheFirstSession(FakeMidiManagerClient* client) {
    EXPECT_FALSE(manager_->start_initialization_is_called_);
    EXPECT_EQ(0U, manager_->GetClientCount());
    EXPECT_EQ(0U, manager_->GetPendingClientCount());
    manager_->StartSession(client, client->get_client_id());
    EXPECT_EQ(0U, manager_->GetClientCount());
    EXPECT_EQ(1U, manager_->GetPendingClientCount());
    EXPECT_TRUE(manager_->start_initialization_is_called_);
    EXPECT_EQ(0U, manager_->GetClientCount());
    EXPECT_EQ(1U, manager_->GetPendingClientCount());
    EXPECT_TRUE(manager_->start_initialization_is_called_);
  }

  void StartTheSecondSession(FakeMidiManagerClient* client) {
    EXPECT_TRUE(manager_->start_initialization_is_called_);
    EXPECT_EQ(0U, manager_->GetClientCount());
    EXPECT_EQ(1U, manager_->GetPendingClientCount());

    // StartInitialization() should not be called for the second session.
    manager_->start_initialization_is_called_ = false;
    manager_->StartSession(client, client->get_client_id());
    EXPECT_FALSE(manager_->start_initialization_is_called_);
  }

  void EndSession(FakeMidiManagerClient* client, size_t before, size_t after) {
    EXPECT_EQ(before, manager_->GetClientCount());
    manager_->EndSession(client);
    EXPECT_EQ(after, manager_->GetClientCount());
  }

  void CompleteInitialization(MidiResult result) {
    manager_->CallCompleteInitialization(result);
  }

 private:
  scoped_ptr<base::MessageLoop> message_loop_;
  scoped_ptr<FakeMidiManager> manager_;

  DISALLOW_COPY_AND_ASSIGN(MidiManagerTest);
};

TEST_F(MidiManagerTest, StartAndEndSession) {
  scoped_ptr<FakeMidiManagerClient> client;
  client.reset(new FakeMidiManagerClient(0));

  StartTheFirstSession(client.get());
  CompleteInitialization(MIDI_OK);
  EXPECT_EQ(MIDI_OK, client->WaitForResult());
  EndSession(client.get(), 1U, 0U);
}

TEST_F(MidiManagerTest, StartAndEndSessionWithError) {
  scoped_ptr<FakeMidiManagerClient> client;
  client.reset(new FakeMidiManagerClient(1));

  StartTheFirstSession(client.get());
  CompleteInitialization(MIDI_INITIALIZATION_ERROR);
  EXPECT_EQ(MIDI_INITIALIZATION_ERROR, client->WaitForResult());
  EndSession(client.get(), 0U, 0U);
}

TEST_F(MidiManagerTest, StartMultipleSessions) {
  scoped_ptr<FakeMidiManagerClient> client1;
  scoped_ptr<FakeMidiManagerClient> client2;
  client1.reset(new FakeMidiManagerClient(0));
  client2.reset(new FakeMidiManagerClient(1));

  StartTheFirstSession(client1.get());
  StartTheSecondSession(client2.get());
  CompleteInitialization(MIDI_OK);
  EXPECT_EQ(MIDI_OK, client1->WaitForResult());
  EXPECT_EQ(MIDI_OK, client2->WaitForResult());
  EndSession(client1.get(), 2U, 1U);
  EndSession(client2.get(), 1U, 0U);
}

TEST_F(MidiManagerTest, CreateMidiManager) {
  scoped_ptr<FakeMidiManagerClient> client;
  client.reset(new FakeMidiManagerClient(0));

  scoped_ptr<MidiManager> manager(MidiManager::Create());
  manager->StartSession(client.get(), client->get_client_id());
  EXPECT_EQ(MIDI_OK, client->WaitForResult());
}

}  // namespace

}  // namespace media
<commit_msg>Fix build without any specific MidiManager provided<commit_after>// Copyright 2014 The Chromium 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 "media/midi/midi_manager.h"

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

namespace {

class FakeMidiManager : public MidiManager {
 public:
  FakeMidiManager() : start_initialization_is_called_(false) {}
  virtual ~FakeMidiManager() {}

  // MidiManager implementation.
  virtual void StartInitialization() OVERRIDE {
    start_initialization_is_called_ = true;
  }

  virtual void DispatchSendMidiData(MidiManagerClient* client,
                                    uint32 port_index,
                                    const std::vector<uint8>& data,
                                    double timestamp) OVERRIDE {}

  // Utility functions for testing.
  void CallCompleteInitialization(MidiResult result) {
    CompleteInitialization(result);
  }

  size_t GetClientCount() const {
    return get_clients_size_for_testing();
  }

  size_t GetPendingClientCount() const {
    return get_pending_clients_size_for_testing();
  }

  bool start_initialization_is_called_;

 private:
  DISALLOW_COPY_AND_ASSIGN(FakeMidiManager);
};

class FakeMidiManagerClient : public MidiManagerClient {
 public:
  explicit FakeMidiManagerClient(int client_id)
      : client_id_(client_id),
        result_(MIDI_NOT_SUPPORTED),
        wait_for_result_(true) {}
  virtual ~FakeMidiManagerClient() {}

  // MidiManagerClient implementation.
  virtual void CompleteStartSession(int client_id, MidiResult result) OVERRIDE {
    CHECK_EQ(client_id_, client_id);
    result_ = result;
    wait_for_result_ = false;
  }

  virtual void ReceiveMidiData(uint32 port_index, const uint8* data,
                               size_t size, double timestamp) OVERRIDE {}
  virtual void AccumulateMidiBytesSent(size_t size) OVERRIDE {}

  int get_client_id() const { return client_id_; }
  MidiResult get_result() const { return result_; }

  MidiResult WaitForResult() {
    base::RunLoop run_loop;
    // CompleteStartSession() is called inside the message loop on the same
    // thread. Protection for |wait_for_result_| is not needed.
    while (wait_for_result_)
      run_loop.RunUntilIdle();
    return get_result();
  }

 private:
  int client_id_;
  MidiResult result_;
  bool wait_for_result_;

  DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
};

class MidiManagerTest : public ::testing::Test {
 public:
  MidiManagerTest()
      : message_loop_(new base::MessageLoop), manager_(new FakeMidiManager) {}
  virtual ~MidiManagerTest() {}

 protected:
  void StartTheFirstSession(FakeMidiManagerClient* client) {
    EXPECT_FALSE(manager_->start_initialization_is_called_);
    EXPECT_EQ(0U, manager_->GetClientCount());
    EXPECT_EQ(0U, manager_->GetPendingClientCount());
    manager_->StartSession(client, client->get_client_id());
    EXPECT_EQ(0U, manager_->GetClientCount());
    EXPECT_EQ(1U, manager_->GetPendingClientCount());
    EXPECT_TRUE(manager_->start_initialization_is_called_);
    EXPECT_EQ(0U, manager_->GetClientCount());
    EXPECT_EQ(1U, manager_->GetPendingClientCount());
    EXPECT_TRUE(manager_->start_initialization_is_called_);
  }

  void StartTheSecondSession(FakeMidiManagerClient* client) {
    EXPECT_TRUE(manager_->start_initialization_is_called_);
    EXPECT_EQ(0U, manager_->GetClientCount());
    EXPECT_EQ(1U, manager_->GetPendingClientCount());

    // StartInitialization() should not be called for the second session.
    manager_->start_initialization_is_called_ = false;
    manager_->StartSession(client, client->get_client_id());
    EXPECT_FALSE(manager_->start_initialization_is_called_);
  }

  void EndSession(FakeMidiManagerClient* client, size_t before, size_t after) {
    EXPECT_EQ(before, manager_->GetClientCount());
    manager_->EndSession(client);
    EXPECT_EQ(after, manager_->GetClientCount());
  }

  void CompleteInitialization(MidiResult result) {
    manager_->CallCompleteInitialization(result);
  }

 private:
  scoped_ptr<base::MessageLoop> message_loop_;
  scoped_ptr<FakeMidiManager> manager_;

  DISALLOW_COPY_AND_ASSIGN(MidiManagerTest);
};

TEST_F(MidiManagerTest, StartAndEndSession) {
  scoped_ptr<FakeMidiManagerClient> client;
  client.reset(new FakeMidiManagerClient(0));

  StartTheFirstSession(client.get());
  CompleteInitialization(MIDI_OK);
  EXPECT_EQ(MIDI_OK, client->WaitForResult());
  EndSession(client.get(), 1U, 0U);
}

TEST_F(MidiManagerTest, StartAndEndSessionWithError) {
  scoped_ptr<FakeMidiManagerClient> client;
  client.reset(new FakeMidiManagerClient(1));

  StartTheFirstSession(client.get());
  CompleteInitialization(MIDI_INITIALIZATION_ERROR);
  EXPECT_EQ(MIDI_INITIALIZATION_ERROR, client->WaitForResult());
  EndSession(client.get(), 0U, 0U);
}

TEST_F(MidiManagerTest, StartMultipleSessions) {
  scoped_ptr<FakeMidiManagerClient> client1;
  scoped_ptr<FakeMidiManagerClient> client2;
  client1.reset(new FakeMidiManagerClient(0));
  client2.reset(new FakeMidiManagerClient(1));

  StartTheFirstSession(client1.get());
  StartTheSecondSession(client2.get());
  CompleteInitialization(MIDI_OK);
  EXPECT_EQ(MIDI_OK, client1->WaitForResult());
  EXPECT_EQ(MIDI_OK, client2->WaitForResult());
  EndSession(client1.get(), 2U, 1U);
  EndSession(client2.get(), 1U, 0U);
}

TEST_F(MidiManagerTest, CreateMidiManager) {
  scoped_ptr<FakeMidiManagerClient> client;
  client.reset(new FakeMidiManagerClient(0));

  scoped_ptr<MidiManager> manager(MidiManager::Create());
  manager->StartSession(client.get(), client->get_client_id());
  // This #ifdef needs to be identical to the one in media/midi/midi_manager.cc
#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
    !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
  EXPECT_EQ(MIDI_NOT_SUPPORTED, client->WaitForResult());
#else
  EXPECT_EQ(MIDI_OK, client->WaitForResult());
#endif
}

}  // namespace

}  // namespace media
<|endoftext|>


<commit_before>#include "multiverso/table_interface.h"
#include "multiverso/util/log.h"
#include "multiverso/util/waiter.h"
#include "multiverso/zoo.h"
#include "multiverso/dashboard.h"
#include "multiverso/updater/updater.h"

namespace multiverso {

WorkerTable::WorkerTable() {
  table_id_ = Zoo::Get()->RegisterTable(this);
}

ServerTable::ServerTable() {
  Zoo::Get()->RegisterTable(this);
}

void WorkerTable::Get(Blob keys,
                      const GeneralOption* option) {
  MONITOR_BEGIN(WORKER_TABLE_SYNC_GET)
  Wait(GetAsync(keys, option));
  MONITOR_END(WORKER_TABLE_SYNC_GET)
}

void WorkerTable::Add(Blob keys, Blob values,
                      const UpdateOption* option) {
  MONITOR_BEGIN(WORKER_TABLE_SYNC_ADD)
  Wait(AddAsync(keys, values, option));
  //AddAsync(keys, values, option);
  MONITOR_END(WORKER_TABLE_SYNC_ADD)
}

int WorkerTable::GetAsync(Blob keys,
                          const GeneralOption* option) {
  int id = msg_id_++;
  waitings_[id] = new Waiter();
  MessagePtr msg(new Message());
  msg->set_src(Zoo::Get()->rank());
  msg->set_type(MsgType::Request_Get);
  msg->set_msg_id(id);
  msg->set_table_id(table_id_);
  msg->Push(keys);
  // Add general option if necessary
  if (option != nullptr) {
    Blob general_option(option->data(), option->size());
    msg->Push(general_option);
  }
  Zoo::Get()->SendTo(actor::kWorker, msg);
  return id;
}

int WorkerTable::AddAsync(Blob keys, Blob values,
                          const UpdateOption* option) {
  int id = msg_id_++;
  waitings_[id] = new Waiter();
  MessagePtr msg(new Message());
  msg->set_src(Zoo::Get()->rank());
  msg->set_type(MsgType::Request_Add);
  msg->set_msg_id(id);
  msg->set_table_id(table_id_);
  msg->Push(keys);
  msg->Push(values);
  // Add update option if necessary
  if (option != nullptr) {
    Blob update_option(option->data(), option->size());
    msg->Push(update_option);
  }
  Zoo::Get()->SendTo(actor::kWorker, msg);
  return id;
}

void WorkerTable::Wait(int id) {
  CHECK(waitings_.find(id) != waitings_.end());
  CHECK(waitings_[id] != nullptr);
  waitings_[id]->Wait();
  delete waitings_[id];
  waitings_[id] = nullptr;
}

void WorkerTable::Reset(int msg_id, int num_wait) {
  CHECK_NOTNULL(waitings_[msg_id]);
  waitings_[msg_id]->Reset(num_wait);
}

void WorkerTable::Notify(int id) {
  CHECK_NOTNULL(waitings_[id]);
  waitings_[id]->Notify();
}

WorkerTable* TableHelper::CreateTable() {
  if (Zoo::Get()->server_rank() >= 0) {
    CreateServerTable();
  }
  if (Zoo::Get()->worker_rank() >= 0) {
    return CreateWorkerTable();
  }
  return nullptr;
}

}  // namespace multiverso
<commit_msg>making add to async-mode<commit_after>#include "multiverso/table_interface.h"
#include "multiverso/util/log.h"
#include "multiverso/util/waiter.h"
#include "multiverso/zoo.h"
#include "multiverso/dashboard.h"
#include "multiverso/updater/updater.h"

namespace multiverso {

WorkerTable::WorkerTable() {
  table_id_ = Zoo::Get()->RegisterTable(this);
}

ServerTable::ServerTable() {
  Zoo::Get()->RegisterTable(this);
}

void WorkerTable::Get(Blob keys,
                      const GeneralOption* option) {
  MONITOR_BEGIN(WORKER_TABLE_SYNC_GET)
  Wait(GetAsync(keys, option));
  MONITOR_END(WORKER_TABLE_SYNC_GET)
}

void WorkerTable::Add(Blob keys, Blob values,
                      const UpdateOption* option) {
  MONITOR_BEGIN(WORKER_TABLE_SYNC_ADD)
  //Wait(AddAsync(keys, values, option));
  AddAsync(keys, values, option);
  MONITOR_END(WORKER_TABLE_SYNC_ADD)
}

int WorkerTable::GetAsync(Blob keys,
                          const GeneralOption* option) {
  int id = msg_id_++;
  waitings_[id] = new Waiter();
  MessagePtr msg(new Message());
  msg->set_src(Zoo::Get()->rank());
  msg->set_type(MsgType::Request_Get);
  msg->set_msg_id(id);
  msg->set_table_id(table_id_);
  msg->Push(keys);
  // Add general option if necessary
  if (option != nullptr) {
    Blob general_option(option->data(), option->size());
    msg->Push(general_option);
  }
  Zoo::Get()->SendTo(actor::kWorker, msg);
  return id;
}

int WorkerTable::AddAsync(Blob keys, Blob values,
                          const UpdateOption* option) {
  int id = msg_id_++;
  waitings_[id] = new Waiter();
  MessagePtr msg(new Message());
  msg->set_src(Zoo::Get()->rank());
  msg->set_type(MsgType::Request_Add);
  msg->set_msg_id(id);
  msg->set_table_id(table_id_);
  msg->Push(keys);
  msg->Push(values);
  // Add update option if necessary
  if (option != nullptr) {
    Blob update_option(option->data(), option->size());
    msg->Push(update_option);
  }
  Zoo::Get()->SendTo(actor::kWorker, msg);
  return id;
}

void WorkerTable::Wait(int id) {
  CHECK(waitings_.find(id) != waitings_.end());
  CHECK(waitings_[id] != nullptr);
  waitings_[id]->Wait();
  delete waitings_[id];
  waitings_[id] = nullptr;
}

void WorkerTable::Reset(int msg_id, int num_wait) {
  CHECK_NOTNULL(waitings_[msg_id]);
  waitings_[msg_id]->Reset(num_wait);
}

void WorkerTable::Notify(int id) {
  CHECK_NOTNULL(waitings_[id]);
  waitings_[id]->Notify();
}

WorkerTable* TableHelper::CreateTable() {
  if (Zoo::Get()->server_rank() >= 0) {
    CreateServerTable();
  }
  if (Zoo::Get()->worker_rank() >= 0) {
    return CreateWorkerTable();
  }
  return nullptr;
}

}  // namespace multiverso
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 Nikhil Marathe ( nsm.nikhil@gmail.com )
 * This file is distributed under the MIT License. Please see
 * LICENSE for details
 */
#include "taglib.h"

#include <errno.h>
#include <string.h>

#include <v8.h>
#include <node_buffer.h>

#include <tfilestream.h>
#include <asffile.h>
#include <mpegfile.h>
#include <vorbisfile.h>
#include <flacfile.h>
#include <oggflacfile.h>
#include <mpcfile.h>
#include <mp4file.h>
#include <wavpackfile.h>
#include <speexfile.h>
#include <trueaudiofile.h>
#include <aifffile.h>
#include <wavfile.h>
#include <apefile.h>
#include <modfile.h>
#include <s3mfile.h>
#include <itfile.h>
#include <xmfile.h>

#include "audioproperties.h"
#include "tag.h"
#include "bufferstream.h"

using namespace v8;
using namespace node;
using namespace node_taglib;

namespace node_taglib {
int CreateFileRefPath(TagLib::FileName path, TagLib::FileRef **ref) {
    TagLib::FileRef *f = NULL;
    int error = 0;
    if (!TagLib::File::isReadable(path)) {
        error = EACCES;
    }
    else {
        f = new TagLib::FileRef(path);

        if ( f->isNull() || !f->tag() )
        {
            error = EINVAL;
            delete f;
        }
    }

    if (error != 0)
        *ref = NULL;
    else
        *ref = f;

    return error;
}

int CreateFileRef(TagLib::IOStream *stream, TagLib::String format, TagLib::FileRef **ref) {
    TagLib::FileRef *f = NULL;
    int error = 0;

    TagLib::File *file = createFile(stream, format);
    if (file == NULL) {
        *ref = NULL;
        return EBADF;
    }

    f = new TagLib::FileRef(file);

    if (f->isNull() || !f->tag())
    {
        error = EINVAL;
        delete f;
    }

    if (error != 0)
        *ref = NULL;
    else
        *ref = f;

    return error;
}

TagLib::File *createFile(TagLib::IOStream *stream, TagLib::String format) {
    TagLib::File *file = 0;
    format = format.upper();
    if (format == "MPEG")
        file = new TagLib::MPEG::File(stream, TagLib::ID3v2::FrameFactory::instance());
    else if (format == "OGG")
        file = new TagLib::Ogg::Vorbis::File(stream);
    else if (format == "OGG/FLAC")
        file = new TagLib::Ogg::FLAC::File(stream);
    else if (format == "FLAC")
        file = new TagLib::FLAC::File(stream, TagLib::ID3v2::FrameFactory::instance());
    else if (format == "MPC")
        file = new TagLib::MPC::File(stream);
    else if (format == "WV")
        file = new TagLib::WavPack::File(stream);
    else if (format == "SPX")
        file = new TagLib::Ogg::Speex::File(stream);
    else if (format == "TTA")
        file = new TagLib::TrueAudio::File(stream);
    else if (format == "MP4")
        file = new TagLib::MP4::File(stream);
    else if (format == "ASF")
        file = new TagLib::ASF::File(stream);
    else if (format == "AIFF")
        file = new TagLib::RIFF::AIFF::File(stream);
    else if (format == "WAV")
        file = new TagLib::RIFF::WAV::File(stream);
    else if (format == "APE")
        file = new TagLib::APE::File(stream);
    // module, nst and wow are possible but uncommon formatensions
    else if (format == "MOD")
        file = new TagLib::Mod::File(stream);
    else if (format == "S3M")
        file = new TagLib::S3M::File(stream);
    else if (format == "IT")
        file = new TagLib::IT::File(stream);
    else if (format == "XM")
        file = new TagLib::XM::File(stream);
    return file;
}

Handle<String> ErrorToString(int error) {
    HandleScope scope;
    std::string err;

    switch (error) {
        case EACCES:
            err = "File is not readable";
            break;

        case EINVAL:
            err = "Failed to extract tags";
            break;

        case EBADF:
            err = "Unknown file format (check format string)";
            break;

        default:
            err = "Unknown error";
            break;
    }

    return scope.Close(String::New(err.c_str(), err.length()));
}

v8::Handle<v8::Value> AsyncReadFile(const v8::Arguments &args) {
    HandleScope scope;

    if (args.Length() < 1) {
        return ThrowException(String::New("Expected string or buffer as first argument"));
    }

    if (args[0]->IsString()) {
        if (args.Length() < 2 || !args[1]->IsFunction())
            return ThrowException(String::New("Expected callback function as second argument"));

    }
    else if (Buffer::HasInstance(args[0])) {
        if (args.Length() < 2 || !args[1]->IsString())
            return ThrowException(String::New("Expected string 'format' as second argument"));
        if (args.Length() < 3 || !args[2]->IsFunction())
            return ThrowException(String::New("Expected callback function as third argument"));
    }
    else {
        return ThrowException(String::New("Expected string or buffer as first argument"));
    }

    AsyncBaton *baton = new AsyncBaton;
    baton->request.data = baton;
    baton->path = 0;
    baton->format = TagLib::String::null;
    baton->stream = 0;
    baton->error = 0;

    if (args[0]->IsString()) {
        String::Utf8Value path(args[0]->ToString());
        baton->path = strdup(*path);
        baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));

    }
    else {
        baton->format = NodeStringToTagLibString(args[1]->ToString());
        baton->stream = new BufferStream(args[0]->ToObject());
        baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
    }

    uv_queue_work(uv_default_loop(), &baton->request, AsyncReadFileDo, (uv_after_work_cb)AsyncReadFileAfter);

    return Undefined();
}

void AsyncReadFileDo(uv_work_t *req) {
    AsyncBaton *baton = static_cast<AsyncBaton*>(req->data);

    TagLib::FileRef *f;

    if (baton->path) {
        baton->error = node_taglib::CreateFileRefPath(baton->path, &f);
    }
    else {
        assert(baton->stream);
        baton->error = node_taglib::CreateFileRef(baton->stream, baton->format, &f);
    }

    if (baton->error == 0) {
        baton->fileRef = f;
    }
}

void AsyncReadFileAfter(uv_work_t *req) {
    AsyncBaton *baton = static_cast<AsyncBaton*>(req->data);
    if (baton->error) {
        Local<Object> error = Object::New();
        error->Set(String::New("code"), Integer::New(baton->error));
        error->Set(String::New("message"), ErrorToString(baton->error));
        Handle<Value> argv[] = { error, Null(), Null() };
        baton->callback->Call(Context::GetCurrent()->Global(), 3, argv);
    }
    else {
        // read the data, put it in objects and delete the fileref
        TagLib::Tag *tag = baton->fileRef->tag();
        Local<Object> tagObj = Object::New();
        if (!tag->isEmpty()) {
            tagObj->Set(String::New("album"), TagLibStringToString(tag->album()));
            tagObj->Set(String::New("artist"), TagLibStringToString(tag->artist()));
            tagObj->Set(String::New("comment"), TagLibStringToString(tag->comment()));
            tagObj->Set(String::New("genre"), TagLibStringToString(tag->genre()));
            tagObj->Set(String::New("title"), TagLibStringToString(tag->title()));
            tagObj->Set(String::New("track"), Integer::New(tag->track()));
            tagObj->Set(String::New("year"), Integer::New(tag->year()));
        }

        TagLib::AudioProperties *props = baton->fileRef->audioProperties();
        Local<Object> propsObj = Object::New();
        if (props) {
            propsObj->Set(String::New("length"), Integer::New(props->length()));
            propsObj->Set(String::New("bitrate"), Integer::New(props->bitrate()));
            propsObj->Set(String::New("sampleRate"), Integer::New(props->sampleRate()));
            propsObj->Set(String::New("channels"), Integer::New(props->channels()));
        }

        Handle<Value> argv[] = { Null(), tagObj, propsObj };
        baton->callback->Call(Context::GetCurrent()->Global(), 3, argv);

        delete baton->fileRef;
        delete baton;
        baton = NULL;
    }
}

Handle<Value> TagLibStringToString( TagLib::String s )
{
    if(s.isEmpty()) {
        return Null();
    }
    else {
        TagLib::ByteVector str = s.data(TagLib::String::UTF16);
        // Strip the Byte Order Mark of the input to avoid node adding a UTF-8
        // Byte Order Mark
        return String::New((uint16_t *)str.mid(2,str.size()-2).data(), s.size());
    }
}

TagLib::String NodeStringToTagLibString( Local<Value> s )
{
    if(s->IsNull()) {
        return TagLib::String::null;
    }
    else {
        String::Utf8Value str(s->ToString());
        return TagLib::String(*str, TagLib::String::UTF8);
    }
}

Handle<Value> AddResolvers(const Arguments &args)
{
    for (int i = 0; i < args.Length(); i++) {
        Local<Value> arg = args[i];
        if (arg->IsFunction()) {
            Persistent<Function> resolver = Persistent<Function>::New(Local<Function>::Cast(arg));
            TagLib::FileRef::addFileTypeResolver(new CallbackResolver(resolver));
        }
    }
}

CallbackResolver::CallbackResolver(Persistent<Function> func)
    : TagLib::FileRef::FileTypeResolver()
    , resolverFunc(func)
    // the constructor is always called in the v8 thread
#ifdef _WIN32
    , created_in(GetCurrentThreadId())
#else
    , created_in(pthread_self())
#endif
{
}

void CallbackResolver::invokeResolverCb(uv_async_t *handle, int status)
{
    AsyncResolverBaton *baton = (AsyncResolverBaton *) handle->data;
    invokeResolver(baton);
    uv_async_send((uv_async_t*) &baton->idler);
    uv_close((uv_handle_t*)&baton->request, 0);
}

void CallbackResolver::stopIdling(uv_async_t *handle, int status)
{
    uv_close((uv_handle_t*) handle, 0);
}

void CallbackResolver::invokeResolver(AsyncResolverBaton *baton)
{
    HandleScope scope;
    Handle<Value> argv[] = { TagLibStringToString(baton->fileName) };
    Local<Value> ret = baton->resolver->resolverFunc->Call(Context::GetCurrent()->Global(), 1, argv);
    if (!ret->IsString()) {
        baton->type = TagLib::String::null;
    }
    else {
        baton->type = NodeStringToTagLibString(ret->ToString()).upper();
    }
}

TagLib::File *CallbackResolver::createFile(TagLib::FileName fileName, bool readAudioProperties, TagLib::AudioProperties::ReadStyle audioPropertiesStyle) const
{
    AsyncResolverBaton baton;
    baton.request.data = (void *) &baton;
    baton.resolver = this;
    baton.fileName = fileName;

#ifdef _WIN32
    if (created_in != GetCurrentThreadId()) {
#else
    if (created_in != pthread_self()) {
#endif
        uv_loop_t *wait_loop = uv_loop_new();
        uv_async_init(wait_loop, &baton.idler, CallbackResolver::stopIdling);

        uv_async_init(uv_default_loop(), &baton.request, invokeResolverCb);
        uv_async_send(&baton.request);
        uv_run(wait_loop);
        uv_loop_delete(wait_loop);
    }
    else {
        invokeResolver(&baton);
    }

    TagLib::FileStream *stream = new TagLib::FileStream(fileName);

    return node_taglib::createFile(stream, baton.type);
}
}

extern "C" {

static void
init (Handle<Object> target)
{
    HandleScope scope;

#ifdef TAGLIB_WITH_ASF
    target->Set(String::NewSymbol("WITH_ASF"), v8::True());
#else
    target->Set(String::NewSymbol("WITH_ASF"), v8::False());
#endif

#ifdef TAGLIB_WITH_MP4
    target->Set(String::NewSymbol("WITH_MP4"), v8::True());
#else
    target->Set(String::NewSymbol("WITH_MP4"), v8::False());
#endif

    NODE_SET_METHOD(target, "read", AsyncReadFile);
#ifdef ENABLE_RESOLVERS
    NODE_SET_METHOD(target, "addResolvers", AddResolvers);
#endif
    Tag::Initialize(target);
}

NODE_MODULE(taglib, init)
}
<commit_msg>add uv_run_mode to uv_run<commit_after>/*
 * Copyright (C) 2009 Nikhil Marathe ( nsm.nikhil@gmail.com )
 * This file is distributed under the MIT License. Please see
 * LICENSE for details
 */
#include "taglib.h"

#include <errno.h>
#include <string.h>

#include <v8.h>
#include <node_buffer.h>

#include <tfilestream.h>
#include <asffile.h>
#include <mpegfile.h>
#include <vorbisfile.h>
#include <flacfile.h>
#include <oggflacfile.h>
#include <mpcfile.h>
#include <mp4file.h>
#include <wavpackfile.h>
#include <speexfile.h>
#include <trueaudiofile.h>
#include <aifffile.h>
#include <wavfile.h>
#include <apefile.h>
#include <modfile.h>
#include <s3mfile.h>
#include <itfile.h>
#include <xmfile.h>

#include "audioproperties.h"
#include "tag.h"
#include "bufferstream.h"

using namespace v8;
using namespace node;
using namespace node_taglib;

namespace node_taglib {
int CreateFileRefPath(TagLib::FileName path, TagLib::FileRef **ref) {
    TagLib::FileRef *f = NULL;
    int error = 0;
    if (!TagLib::File::isReadable(path)) {
        error = EACCES;
    }
    else {
        f = new TagLib::FileRef(path);

        if ( f->isNull() || !f->tag() )
        {
            error = EINVAL;
            delete f;
        }
    }

    if (error != 0)
        *ref = NULL;
    else
        *ref = f;

    return error;
}

int CreateFileRef(TagLib::IOStream *stream, TagLib::String format, TagLib::FileRef **ref) {
    TagLib::FileRef *f = NULL;
    int error = 0;

    TagLib::File *file = createFile(stream, format);
    if (file == NULL) {
        *ref = NULL;
        return EBADF;
    }

    f = new TagLib::FileRef(file);

    if (f->isNull() || !f->tag())
    {
        error = EINVAL;
        delete f;
    }

    if (error != 0)
        *ref = NULL;
    else
        *ref = f;

    return error;
}

TagLib::File *createFile(TagLib::IOStream *stream, TagLib::String format) {
    TagLib::File *file = 0;
    format = format.upper();
    if (format == "MPEG")
        file = new TagLib::MPEG::File(stream, TagLib::ID3v2::FrameFactory::instance());
    else if (format == "OGG")
        file = new TagLib::Ogg::Vorbis::File(stream);
    else if (format == "OGG/FLAC")
        file = new TagLib::Ogg::FLAC::File(stream);
    else if (format == "FLAC")
        file = new TagLib::FLAC::File(stream, TagLib::ID3v2::FrameFactory::instance());
    else if (format == "MPC")
        file = new TagLib::MPC::File(stream);
    else if (format == "WV")
        file = new TagLib::WavPack::File(stream);
    else if (format == "SPX")
        file = new TagLib::Ogg::Speex::File(stream);
    else if (format == "TTA")
        file = new TagLib::TrueAudio::File(stream);
    else if (format == "MP4")
        file = new TagLib::MP4::File(stream);
    else if (format == "ASF")
        file = new TagLib::ASF::File(stream);
    else if (format == "AIFF")
        file = new TagLib::RIFF::AIFF::File(stream);
    else if (format == "WAV")
        file = new TagLib::RIFF::WAV::File(stream);
    else if (format == "APE")
        file = new TagLib::APE::File(stream);
    // module, nst and wow are possible but uncommon formatensions
    else if (format == "MOD")
        file = new TagLib::Mod::File(stream);
    else if (format == "S3M")
        file = new TagLib::S3M::File(stream);
    else if (format == "IT")
        file = new TagLib::IT::File(stream);
    else if (format == "XM")
        file = new TagLib::XM::File(stream);
    return file;
}

Handle<String> ErrorToString(int error) {
    HandleScope scope;
    std::string err;

    switch (error) {
        case EACCES:
            err = "File is not readable";
            break;

        case EINVAL:
            err = "Failed to extract tags";
            break;

        case EBADF:
            err = "Unknown file format (check format string)";
            break;

        default:
            err = "Unknown error";
            break;
    }

    return scope.Close(String::New(err.c_str(), err.length()));
}

v8::Handle<v8::Value> AsyncReadFile(const v8::Arguments &args) {
    HandleScope scope;

    if (args.Length() < 1) {
        return ThrowException(String::New("Expected string or buffer as first argument"));
    }

    if (args[0]->IsString()) {
        if (args.Length() < 2 || !args[1]->IsFunction())
            return ThrowException(String::New("Expected callback function as second argument"));

    }
    else if (Buffer::HasInstance(args[0])) {
        if (args.Length() < 2 || !args[1]->IsString())
            return ThrowException(String::New("Expected string 'format' as second argument"));
        if (args.Length() < 3 || !args[2]->IsFunction())
            return ThrowException(String::New("Expected callback function as third argument"));
    }
    else {
        return ThrowException(String::New("Expected string or buffer as first argument"));
    }

    AsyncBaton *baton = new AsyncBaton;
    baton->request.data = baton;
    baton->path = 0;
    baton->format = TagLib::String::null;
    baton->stream = 0;
    baton->error = 0;

    if (args[0]->IsString()) {
        String::Utf8Value path(args[0]->ToString());
        baton->path = strdup(*path);
        baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));

    }
    else {
        baton->format = NodeStringToTagLibString(args[1]->ToString());
        baton->stream = new BufferStream(args[0]->ToObject());
        baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
    }

    uv_queue_work(uv_default_loop(), &baton->request, AsyncReadFileDo, (uv_after_work_cb)AsyncReadFileAfter);

    return Undefined();
}

void AsyncReadFileDo(uv_work_t *req) {
    AsyncBaton *baton = static_cast<AsyncBaton*>(req->data);

    TagLib::FileRef *f;

    if (baton->path) {
        baton->error = node_taglib::CreateFileRefPath(baton->path, &f);
    }
    else {
        assert(baton->stream);
        baton->error = node_taglib::CreateFileRef(baton->stream, baton->format, &f);
    }

    if (baton->error == 0) {
        baton->fileRef = f;
    }
}

void AsyncReadFileAfter(uv_work_t *req) {
    AsyncBaton *baton = static_cast<AsyncBaton*>(req->data);
    if (baton->error) {
        Local<Object> error = Object::New();
        error->Set(String::New("code"), Integer::New(baton->error));
        error->Set(String::New("message"), ErrorToString(baton->error));
        Handle<Value> argv[] = { error, Null(), Null() };
        baton->callback->Call(Context::GetCurrent()->Global(), 3, argv);
    }
    else {
        // read the data, put it in objects and delete the fileref
        TagLib::Tag *tag = baton->fileRef->tag();
        Local<Object> tagObj = Object::New();
        if (!tag->isEmpty()) {
            tagObj->Set(String::New("album"), TagLibStringToString(tag->album()));
            tagObj->Set(String::New("artist"), TagLibStringToString(tag->artist()));
            tagObj->Set(String::New("comment"), TagLibStringToString(tag->comment()));
            tagObj->Set(String::New("genre"), TagLibStringToString(tag->genre()));
            tagObj->Set(String::New("title"), TagLibStringToString(tag->title()));
            tagObj->Set(String::New("track"), Integer::New(tag->track()));
            tagObj->Set(String::New("year"), Integer::New(tag->year()));
        }

        TagLib::AudioProperties *props = baton->fileRef->audioProperties();
        Local<Object> propsObj = Object::New();
        if (props) {
            propsObj->Set(String::New("length"), Integer::New(props->length()));
            propsObj->Set(String::New("bitrate"), Integer::New(props->bitrate()));
            propsObj->Set(String::New("sampleRate"), Integer::New(props->sampleRate()));
            propsObj->Set(String::New("channels"), Integer::New(props->channels()));
        }

        Handle<Value> argv[] = { Null(), tagObj, propsObj };
        baton->callback->Call(Context::GetCurrent()->Global(), 3, argv);

        delete baton->fileRef;
        delete baton;
        baton = NULL;
    }
}

Handle<Value> TagLibStringToString( TagLib::String s )
{
    if(s.isEmpty()) {
        return Null();
    }
    else {
        TagLib::ByteVector str = s.data(TagLib::String::UTF16);
        // Strip the Byte Order Mark of the input to avoid node adding a UTF-8
        // Byte Order Mark
        return String::New((uint16_t *)str.mid(2,str.size()-2).data(), s.size());
    }
}

TagLib::String NodeStringToTagLibString( Local<Value> s )
{
    if(s->IsNull()) {
        return TagLib::String::null;
    }
    else {
        String::Utf8Value str(s->ToString());
        return TagLib::String(*str, TagLib::String::UTF8);
    }
}

Handle<Value> AddResolvers(const Arguments &args)
{
    for (int i = 0; i < args.Length(); i++) {
        Local<Value> arg = args[i];
        if (arg->IsFunction()) {
            Persistent<Function> resolver = Persistent<Function>::New(Local<Function>::Cast(arg));
            TagLib::FileRef::addFileTypeResolver(new CallbackResolver(resolver));
        }
    }
}

CallbackResolver::CallbackResolver(Persistent<Function> func)
    : TagLib::FileRef::FileTypeResolver()
    , resolverFunc(func)
    // the constructor is always called in the v8 thread
#ifdef _WIN32
    , created_in(GetCurrentThreadId())
#else
    , created_in(pthread_self())
#endif
{
}

void CallbackResolver::invokeResolverCb(uv_async_t *handle, int status)
{
    AsyncResolverBaton *baton = (AsyncResolverBaton *) handle->data;
    invokeResolver(baton);
    uv_async_send((uv_async_t*) &baton->idler);
    uv_close((uv_handle_t*)&baton->request, 0);
}

void CallbackResolver::stopIdling(uv_async_t *handle, int status)
{
    uv_close((uv_handle_t*) handle, 0);
}

void CallbackResolver::invokeResolver(AsyncResolverBaton *baton)
{
    HandleScope scope;
    Handle<Value> argv[] = { TagLibStringToString(baton->fileName) };
    Local<Value> ret = baton->resolver->resolverFunc->Call(Context::GetCurrent()->Global(), 1, argv);
    if (!ret->IsString()) {
        baton->type = TagLib::String::null;
    }
    else {
        baton->type = NodeStringToTagLibString(ret->ToString()).upper();
    }
}

TagLib::File *CallbackResolver::createFile(TagLib::FileName fileName, bool readAudioProperties, TagLib::AudioProperties::ReadStyle audioPropertiesStyle) const
{
    AsyncResolverBaton baton;
    baton.request.data = (void *) &baton;
    baton.resolver = this;
    baton.fileName = fileName;

#ifdef _WIN32
    if (created_in != GetCurrentThreadId()) {
#else
    if (created_in != pthread_self()) {
#endif
        uv_loop_t *wait_loop = uv_loop_new();
        uv_async_init(wait_loop, &baton.idler, CallbackResolver::stopIdling);

        uv_async_init(uv_default_loop(), &baton.request, invokeResolverCb);
        uv_async_send(&baton.request);
        uv_run(wait_loop, UV_RUN_DEFAULT);
        uv_loop_delete(wait_loop);
    }
    else {
        invokeResolver(&baton);
    }

    TagLib::FileStream *stream = new TagLib::FileStream(fileName);

    return node_taglib::createFile(stream, baton.type);
}
}

extern "C" {

static void
init (Handle<Object> target)
{
    HandleScope scope;

#ifdef TAGLIB_WITH_ASF
    target->Set(String::NewSymbol("WITH_ASF"), v8::True());
#else
    target->Set(String::NewSymbol("WITH_ASF"), v8::False());
#endif

#ifdef TAGLIB_WITH_MP4
    target->Set(String::NewSymbol("WITH_MP4"), v8::True());
#else
    target->Set(String::NewSymbol("WITH_MP4"), v8::False());
#endif

    NODE_SET_METHOD(target, "read", AsyncReadFile);
#ifdef ENABLE_RESOLVERS
    NODE_SET_METHOD(target, "addResolvers", AddResolvers);
#endif
    Tag::Initialize(target);
}

NODE_MODULE(taglib, init)
}
<|endoftext|>


<commit_before>#ifndef Src_Ancona_Util_StateMachine_SharedMachine_H_
#define Src_Ancona_Util_StateMachine_SharedMachine_H_

#include <vector>

namespace ild
{

typedef int MachineState;

#define StateType(TypeName) namespace TypeName { enum Type : MachineState {
#define EndStateType ,Count }; }

/**
 * @brief Used to create a state machine that is shared by multiple objects.
 * @author Jeff Swenson
 */
template <class T, class R, class ... ArgsT>
class SharedMachine
{
    public:
        /**
         * @brief Construct and initialize a shared machine
         *
         * @param stateCount The number of states the machine should contain
         */
        SharedMachine(int maxState) : _actions(maxState, nullptr)
        {

        }

        typedef R (T::*MachineAction)(MachineState & state, ArgsT...);

        /**
         * @brief Set the action for the state.
         *
         * @param state State to have the action set.
         * @param action Action to be used for the state.
         */
        void SetAction(const MachineState & state, MachineAction action)
        {
            _actions[state] = action;
        }

        R Update(T & object, MachineState & state, ArgsT ... args)
        {
            return (object.*_actions[state])(state, args ...);
        }
    private:
        std::vector<MachineAction> _actions;
};

}
#endif
<commit_msg>Improve StateMachine Documentation<commit_after>#ifndef Src_Ancona_Util_StateMachine_SharedMachine_H_
#define Src_Ancona_Util_StateMachine_SharedMachine_H_

#include <vector>

namespace ild
{

typedef int MachineState;

#define StateType(TypeName) namespace TypeName { enum Type : MachineState {
#define EndStateType ,Count }; }

/**
 * @brief Used to create a state machine that is shared by multiple objects.
 * @author Jeff Swenson
 */
template <class T, class R, class ... ArgsT>
class SharedMachine
{
    public:
        /**
         * @brief Construct and initialize a shared machine
         *
         * @param stateCount The number of states the machine should contain
         */
        SharedMachine(int maxState) : _actions(maxState, nullptr)
        {

        }

        /**
         * @brief Method Type used by the state machine
         *
         * @param MachineState State the machine is currently in. The machine action may mutate state to change the machine's state.
         * @param ArgsT... The arguments to be passed to the action.
         *
         * @return The result of the action.
         */
        typedef R (T::*MachineAction)(MachineState & state, ArgsT...);

        /**
         * @brief Set the action for the state.
         *
         * @param state State to have the action set.
         * @param action Action to be used for the state.
         */
        void SetAction(const MachineState & state, MachineAction action)
        {
            _actions[state] = action;
        }

        /**
         * @brief Fire the action corresponding to the state on the object.
         *
         * @param object Object that the action method will be called on.
         * @param state State that the object's machine is currently in.  May be mutated by the action to change to the state.
         * @param args Arguments to be passed to the action.
         *
         * @return The result of the action.
         */
        R Update(T & object, MachineState & state, ArgsT ... args)
        {
            return (object.*_actions[state])(state, args ...);
        }
    private:
        std::vector<MachineAction> _actions;
};

}
#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sbamultiplex.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 06:59:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"

#ifndef _SBA_MULTIPLEX_HXX
#include "sbamultiplex.hxx"
#endif
using namespace dbaui;

//==================================================================
// the listener multiplexers
//==================================================================

// XStatusListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXStatusMultiplexer, ::com::sun::star::frame::XStatusListener)

void SAL_CALL SbaXStatusMultiplexer::statusChanged(const ::com::sun::star::frame::FeatureStateEvent& e) throw (::com::sun::star::uno::RuntimeException)
{
    m_aLastKnownStatus = e;
    m_aLastKnownStatus.Source = &m_rParent;
    ::cppu::OInterfaceIteratorHelper aIt( *this );
    while ( aIt.hasMoreElements() )
        static_cast< ::com::sun::star::frame::XStatusListener* >( aIt.next() )->statusChanged( m_aLastKnownStatus );
}                                                                                \

// LoadListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, loaded, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, unloaded, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, unloading, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, reloading, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, reloaded, ::com::sun::star::lang::EventObject)

// ::com::sun::star::sdbc::XRowSetListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXRowSetMultiplexer, ::com::sun::star::sdbc::XRowSetListener)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, ::com::sun::star::sdbc::XRowSetListener, cursorMoved, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, ::com::sun::star::sdbc::XRowSetListener, rowChanged, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, ::com::sun::star::sdbc::XRowSetListener, rowSetChanged, ::com::sun::star::lang::EventObject)

// ::com::sun::star::sdb::XRowSetApproveListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXRowSetApproveMultiplexer, ::com::sun::star::sdb::XRowSetApproveListener)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, ::com::sun::star::sdb::XRowSetApproveListener, approveCursorMove, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, ::com::sun::star::sdb::XRowSetApproveListener, approveRowChange, ::com::sun::star::sdb::RowChangeEvent)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, ::com::sun::star::sdb::XRowSetApproveListener, approveRowSetChange, ::com::sun::star::lang::EventObject)

// ::com::sun::star::sdb::XSQLErrorListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXSQLErrorMultiplexer, ::com::sun::star::sdb::XSQLErrorListener)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXSQLErrorMultiplexer, ::com::sun::star::sdb::XSQLErrorListener, errorOccured, ::com::sun::star::sdb::SQLErrorEvent)

// ::com::sun::star::form::XDatabaseParameterListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXParameterMultiplexer, ::com::sun::star::form::XDatabaseParameterListener)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXParameterMultiplexer, ::com::sun::star::form::XDatabaseParameterListener, approveParameter, ::com::sun::star::form::DatabaseParameterEvent)

// ::com::sun::star::form::XSubmitListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXSubmitMultiplexer, ::com::sun::star::form::XSubmitListener)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXSubmitMultiplexer, ::com::sun::star::form::XSubmitListener, approveSubmit, ::com::sun::star::lang::EventObject)

// ::com::sun::star::form::XResetListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXResetMultiplexer, ::com::sun::star::form::XResetListener)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXResetMultiplexer, ::com::sun::star::form::XResetListener, approveReset, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXResetMultiplexer, ::com::sun::star::form::XResetListener, resetted, ::com::sun::star::lang::EventObject)

// ::com::sun::star::beans::XPropertyChangeListener
IMPLEMENT_PROPERTY_MULTIPLEXER(SbaXPropertyChangeMultiplexer, ::com::sun::star::beans::XPropertyChangeListener, propertyChange, ::com::sun::star::beans::PropertyChangeEvent, (::com::sun::star::uno::RuntimeException))

// ::com::sun::star::beans::XVetoableChangeListener
IMPLEMENT_PROPERTY_MULTIPLEXER(SbaXVetoableChangeMultiplexer, ::com::sun::star::beans::XVetoableChangeListener, vetoableChange, ::com::sun::star::beans::PropertyChangeEvent, (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException))

// ::com::sun::star::beans::XPropertiesChangeListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXPropertiesChangeMultiplexer, ::com::sun::star::beans::XPropertiesChangeListener);
void SbaXPropertiesChangeMultiplexer::propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& aEvts) throw(::com::sun::star::uno::RuntimeException)
{
    // the SbaXPropertiesChangeMultiplexer doesn't care about the property names a listener logs on for, it simply
    // forwards _all_ changes to _all_ listeners

    ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent> aMulti(aEvts);
    ::com::sun::star::beans::PropertyChangeEvent* pMulti = aMulti.getArray();
    for (sal_uInt16 i=0; i<aMulti.getLength(); ++i, ++pMulti)
        pMulti->Source = &m_rParent;

    ::cppu::OInterfaceIteratorHelper aIt(*this);
    while (aIt.hasMoreElements())
        ((::com::sun::star::beans::XPropertiesChangeListener*)aIt.next())->propertiesChange(aMulti);
}

<commit_msg>INTEGRATION: CWS changefileheader (1.6.258); FILE MERGED 2008/03/31 13:27:08 rt 1.6.258.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: sbamultiplex.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"

#ifndef _SBA_MULTIPLEX_HXX
#include "sbamultiplex.hxx"
#endif
using namespace dbaui;

//==================================================================
// the listener multiplexers
//==================================================================

// XStatusListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXStatusMultiplexer, ::com::sun::star::frame::XStatusListener)

void SAL_CALL SbaXStatusMultiplexer::statusChanged(const ::com::sun::star::frame::FeatureStateEvent& e) throw (::com::sun::star::uno::RuntimeException)
{
    m_aLastKnownStatus = e;
    m_aLastKnownStatus.Source = &m_rParent;
    ::cppu::OInterfaceIteratorHelper aIt( *this );
    while ( aIt.hasMoreElements() )
        static_cast< ::com::sun::star::frame::XStatusListener* >( aIt.next() )->statusChanged( m_aLastKnownStatus );
}                                                                                \

// LoadListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, loaded, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, unloaded, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, unloading, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, reloading, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, ::com::sun::star::form::XLoadListener, reloaded, ::com::sun::star::lang::EventObject)

// ::com::sun::star::sdbc::XRowSetListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXRowSetMultiplexer, ::com::sun::star::sdbc::XRowSetListener)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, ::com::sun::star::sdbc::XRowSetListener, cursorMoved, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, ::com::sun::star::sdbc::XRowSetListener, rowChanged, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, ::com::sun::star::sdbc::XRowSetListener, rowSetChanged, ::com::sun::star::lang::EventObject)

// ::com::sun::star::sdb::XRowSetApproveListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXRowSetApproveMultiplexer, ::com::sun::star::sdb::XRowSetApproveListener)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, ::com::sun::star::sdb::XRowSetApproveListener, approveCursorMove, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, ::com::sun::star::sdb::XRowSetApproveListener, approveRowChange, ::com::sun::star::sdb::RowChangeEvent)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, ::com::sun::star::sdb::XRowSetApproveListener, approveRowSetChange, ::com::sun::star::lang::EventObject)

// ::com::sun::star::sdb::XSQLErrorListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXSQLErrorMultiplexer, ::com::sun::star::sdb::XSQLErrorListener)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXSQLErrorMultiplexer, ::com::sun::star::sdb::XSQLErrorListener, errorOccured, ::com::sun::star::sdb::SQLErrorEvent)

// ::com::sun::star::form::XDatabaseParameterListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXParameterMultiplexer, ::com::sun::star::form::XDatabaseParameterListener)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXParameterMultiplexer, ::com::sun::star::form::XDatabaseParameterListener, approveParameter, ::com::sun::star::form::DatabaseParameterEvent)

// ::com::sun::star::form::XSubmitListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXSubmitMultiplexer, ::com::sun::star::form::XSubmitListener)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXSubmitMultiplexer, ::com::sun::star::form::XSubmitListener, approveSubmit, ::com::sun::star::lang::EventObject)

// ::com::sun::star::form::XResetListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXResetMultiplexer, ::com::sun::star::form::XResetListener)
IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXResetMultiplexer, ::com::sun::star::form::XResetListener, approveReset, ::com::sun::star::lang::EventObject)
IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXResetMultiplexer, ::com::sun::star::form::XResetListener, resetted, ::com::sun::star::lang::EventObject)

// ::com::sun::star::beans::XPropertyChangeListener
IMPLEMENT_PROPERTY_MULTIPLEXER(SbaXPropertyChangeMultiplexer, ::com::sun::star::beans::XPropertyChangeListener, propertyChange, ::com::sun::star::beans::PropertyChangeEvent, (::com::sun::star::uno::RuntimeException))

// ::com::sun::star::beans::XVetoableChangeListener
IMPLEMENT_PROPERTY_MULTIPLEXER(SbaXVetoableChangeMultiplexer, ::com::sun::star::beans::XVetoableChangeListener, vetoableChange, ::com::sun::star::beans::PropertyChangeEvent, (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException))

// ::com::sun::star::beans::XPropertiesChangeListener
IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXPropertiesChangeMultiplexer, ::com::sun::star::beans::XPropertiesChangeListener);
void SbaXPropertiesChangeMultiplexer::propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& aEvts) throw(::com::sun::star::uno::RuntimeException)
{
    // the SbaXPropertiesChangeMultiplexer doesn't care about the property names a listener logs on for, it simply
    // forwards _all_ changes to _all_ listeners

    ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent> aMulti(aEvts);
    ::com::sun::star::beans::PropertyChangeEvent* pMulti = aMulti.getArray();
    for (sal_uInt16 i=0; i<aMulti.getLength(); ++i, ++pMulti)
        pMulti->Source = &m_rParent;

    ::cppu::OInterfaceIteratorHelper aIt(*this);
    while (aIt.hasMoreElements())
        ((::com::sun::star::beans::XPropertiesChangeListener*)aIt.next())->propertiesChange(aMulti);
}

<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Graphics/OsgSkeletonRepresentation.h"

#include "SurgSim/Framework/ApplicationData.h"
#include "SurgSim/Framework/FrameworkConvert.h"
#include "SurgSim/Framework/Log.h"
#include "SurgSim/Framework/ObjectFactory.h"
#include "SurgSim/Framework/Runtime.h"
#include "SurgSim/Graphics/OsgMaterial.h"
#include "SurgSim/Graphics/OsgModel.h"
#include "SurgSim/Graphics/OsgRigidTransformConversions.h"
#include "SurgSim/Graphics/OsgShader.h"

#include <map>

#include <boost/thread.hpp>

#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Geode>
#include <osg/PositionAttitudeTransform>

#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/RigTransformHardware>
#include <osgAnimation/UpdateBone>

#include <osgDB/ReadFile>

namespace
{

/// Visitor to collect information about the tree that we are using, collect all the
/// osgAnimation::Bone nodes in it and add stacked transform elements to them so
/// we can manipulate them, also switches the skinning to Hardware
class BoneMapCreator : public osg::NodeVisitor
{
public:
	/// Single argument constructor.
	/// \param hardwareShader The shader which does the skinning.
	BoneMapCreator(osg::Shader* hardwareShader) :
		NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), m_shader(hardwareShader) {}

	/// Traverse the given tree and collect the bone data in them.
	/// Also setup for hardware skinning, if a hardware shader is provided.
	/// \param node The root node of the skeleton tree that needs to be traversed.
	void apply(osg::Node& node)
	{
		// Look for the transformation root ..
		if (m_rootTransform == nullptr)
		{
			m_rootTransform = dynamic_cast<osg::MatrixTransform*>(&node);
		}

		// Parse the bone data.
		osgAnimation::Bone* bone = dynamic_cast<osgAnimation::Bone*>(&node);
		if (bone != nullptr)
		{
			SurgSim::Graphics::OsgSkeletonBoneData data;
			data.bone = bone;
			osgAnimation::UpdateMatrixTransform* callback =
				dynamic_cast<osgAnimation::UpdateMatrixTransform*>(bone->getUpdateCallback());

			// If we can't find this callback, replace with the default
			if (callback == nullptr)
			{
				bone->setDefaultUpdateCallback();
				callback = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(bone->getUpdateCallback());
			}

			SURGSIM_ASSERT(callback != nullptr) << "Could neither find nor create the appropriate BoneUpdate callback";

			// Push these transformations onto the stack so we can manipulate them
			data.rotation = new osgAnimation::StackedQuaternionElement("OssRotation");
			callback->getStackedTransforms().push_back(data.rotation);
			data.rotation->setQuaternion(osg::Quat());
			data.translation = new osgAnimation::StackedTranslateElement("OssTranslation");
			callback->getStackedTransforms().push_back(data.translation);

			SURGSIM_ASSERT(m_boneData.find(bone->getName()) == m_boneData.end())
				<< "There already exists a bone with name, " << bone->getName()
				<< ", in this skeleton. Cannot create a duplicate.";

			m_boneData[bone->getName()] = data;
		}

		// Setup for hardware skinning.
		if (m_shader != nullptr)
		{
			osg::Geode* meshGeode= dynamic_cast<osg::Geode*>(&node);
			if (nullptr != meshGeode)
			{
				osgAnimation::RigTransformHardware* rigTransform = new osgAnimation::RigTransformHardware();
				osg::Shader* shader = new osg::Shader(*m_shader);
				rigTransform->setShader(shader);

				for (size_t i = 0; i < meshGeode->getDrawableList().size(); ++i)
				{
					auto rigGeometry = dynamic_cast<osgAnimation::RigGeometry*>(meshGeode->getDrawable(i));
					if (nullptr != rigGeometry)
					{
						rigGeometry->setRigTransformImplementation(rigTransform);
					}
				}
			}
		}
		traverse(node);
	}

	/// \return The bone data that had been collected.
	std::map<std::string, SurgSim::Graphics::OsgSkeletonBoneData> getMap()
	{
		return m_boneData;
	}

	/// \return The root node of the skeleton on which the transform is set.
	osg::ref_ptr<osg::MatrixTransform> getRootTransform()
	{
		return m_rootTransform;
	}

private:
	/// The root bone of the skeleton where the global transform is set.
	osg::ref_ptr<osg::MatrixTransform> m_rootTransform;

	/// The hardware skinning shader.
	osg::ref_ptr<osg::Shader> m_shader;

	/// The bone data from the skeleton.
	std::map<std::string, SurgSim::Graphics::OsgSkeletonBoneData> m_boneData;
};

}

namespace SurgSim
{
namespace Graphics
{
SURGSIM_REGISTER(SurgSim::Framework::Component,
				 SurgSim::Graphics::OsgSkeletonRepresentation, OsgSkeletonRepresentation);

OsgSkeletonRepresentation::OsgSkeletonRepresentation(const std::string& name) :
	Representation(name),
	OsgRepresentation(name),
	SkeletonRepresentation(name)
{
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(OsgSkeletonRepresentation, std::string,
		SkinningShaderFileName, getSkinningShaderFileName, setSkinningShaderFileName);
}

void OsgSkeletonRepresentation::loadModel(const std::string& fileName)
{
	SURGSIM_ASSERT(!isInitialized()) << "Cannot load model after OsgSkeletonRepresentation had been initialized.";

	auto model = std::make_shared<OsgModel>();
	model->load(fileName);
	setModel(model);
}

void OsgSkeletonRepresentation::setModel(std::shared_ptr<SurgSim::Framework::Asset> model)
{
	SURGSIM_ASSERT(!isInitialized()) << "Cannot set model after OsgSkeletonRepresentation had been initialized.";

	auto osgModel = std::dynamic_pointer_cast<OsgModel>(model);

	SURGSIM_ASSERT(model == nullptr || osgModel != nullptr) << "OsgSkeletonRepresentation expects an OsgModel.";

	m_model = osgModel;
}

std::shared_ptr<Model> OsgSkeletonRepresentation::getModel() const
{
	return m_model;
}

void OsgSkeletonRepresentation::setSkinningShaderFileName(std::string fileName)
{
	m_skinningShaderFileName = fileName;
}

std::string OsgSkeletonRepresentation::getSkinningShaderFileName()
{
	return m_skinningShaderFileName;
}

void OsgSkeletonRepresentation::setBonePose(const std::string& name, const SurgSim::Math::RigidTransform3d& pose)
{
	auto boneData = m_boneData.find(name);
	if (boneData != m_boneData.end())
	{
		boost::lock_guard<boost::mutex> lock(m_boneDataMutex);
		boneData->second.pose = pose;
	}
	else
	{
		SURGSIM_LOG_WARNING(SurgSim::Framework::Logger::getDefaultLogger())
			<< "OsgSkeletonRepresentation::setBonePose(): Bone with name, " << name << ", is not present in mesh."
			<< "Cannot set pose.";
	}
}

void OsgSkeletonRepresentation::doUpdate(double dt)
{
	{
		boost::lock_guard<boost::mutex> lock(m_boneDataMutex);
		// Update the pose of all the bones.
		for (auto& boneData : m_boneData)
		{
			std::pair<osg::Quat, osg::Vec3d> pose = toOsg(boneData.second.pose);
			boneData.second.rotation->setQuaternion(pose.first);
			boneData.second.translation->setTranslate(pose.second);
		}
	}

	// Update the position of the rest of the bones.
	m_base->accept(*m_updateVisitor);
	++m_frameCount;
	m_updateVisitor->setTraversalNumber(m_frameCount);
}

bool OsgSkeletonRepresentation::doInitialize()
{
	bool result = true;

	std::string shaderFilename;
	if (m_skinningShaderFileName.empty())
	{
		SURGSIM_LOG_SEVERE(SurgSim::Framework::Logger::getDefaultLogger())
			<< "OsgSkeletonRepresentation::doInitialize(): Skinning shader file not set.";
		result = false;
	}
	else
	{
		getRuntime()->getApplicationData()->tryFindFile(m_skinningShaderFileName, &shaderFilename);
	}

	if (result)
	{
		if (shaderFilename.empty())
		{
			SURGSIM_LOG_SEVERE(SurgSim::Framework::Logger::getDefaultLogger())
				<< "OsgSkeletonRepresentation::doInitialize(): Skinning shader file (" << m_skinningShaderFileName
				<< ") not found.";
			result = false;
		}
		else
		{
			m_skinningShader = new osg::Shader(osg::Shader::VERTEX);
			result = m_skinningShader->loadShaderSourceFromFile(shaderFilename);
		}
	}

	if (result)
	{
		if (m_model == nullptr || std::dynamic_pointer_cast<OsgModel>(m_model) == nullptr)
		{
			SURGSIM_LOG_SEVERE(SurgSim::Framework::Logger::getDefaultLogger())
				<< "OsgSkeletonRepresentation::doInitialize(): model is not set.";
			result = false;
		}
		else
		{
			m_skeleton = dynamic_cast<osg::Node*>(std::dynamic_pointer_cast<OsgModel>(m_model)->getOsgNode().get());
			result = nullptr != m_skeleton;
			SURGSIM_ASSERT(result)
				<< "OsgSkeletonRepresentation::doInitialize(): model does not have a valid osgNode.";
		}
	}

	if (result)
	{
		// Traverse the skeleton and collect bone data.
		BoneMapCreator mapCreator(m_skinningShader);
		mapCreator.traverse(*m_skeleton.get());
		m_boneData = mapCreator.getMap();
		if (m_boneData.size() == 0)
		{
			SURGSIM_LOG_SEVERE(SurgSim::Framework::Logger::getDefaultLogger())
				<< "Could not find any osgAnimation::Bone nodes in tree with root <" + m_skeleton->getName() + ">";
		}
		m_base = mapCreator.getRootTransform();

		// Setup the transform updater for the skeleton.
		m_updateVisitor = new osgUtil::UpdateVisitor();
		m_frameCount = 0;
		m_updateVisitor->setTraversalNumber(m_frameCount);
		m_base->accept(*m_updateVisitor);

		// Add the bone skeleton as a child to m_transform
		m_transform->addChild(m_base.get());
	}

	return result;
}

}; // Graphics
}; // SurgSim
<commit_msg>Order includes according to OSS code standards.<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Graphics/OsgSkeletonRepresentation.h"

#include <map>

#include <boost/thread.hpp>

#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Geode>
#include <osg/PositionAttitudeTransform>

#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/RigTransformHardware>
#include <osgAnimation/UpdateBone>

#include <osgDB/ReadFile>

#include "SurgSim/Framework/ApplicationData.h"
#include "SurgSim/Framework/FrameworkConvert.h"
#include "SurgSim/Framework/Log.h"
#include "SurgSim/Framework/ObjectFactory.h"
#include "SurgSim/Framework/Runtime.h"
#include "SurgSim/Graphics/OsgMaterial.h"
#include "SurgSim/Graphics/OsgModel.h"
#include "SurgSim/Graphics/OsgRigidTransformConversions.h"
#include "SurgSim/Graphics/OsgShader.h"

namespace
{

/// Visitor to collect information about the tree that we are using, collect all the
/// osgAnimation::Bone nodes in it and add stacked transform elements to them so
/// we can manipulate them, also switches the skinning to Hardware
class BoneMapCreator : public osg::NodeVisitor
{
public:
	/// Single argument constructor.
	/// \param hardwareShader The shader which does the skinning.
	BoneMapCreator(osg::Shader* hardwareShader) :
		NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), m_shader(hardwareShader) {}

	/// Traverse the given tree and collect the bone data in them.
	/// Also setup for hardware skinning, if a hardware shader is provided.
	/// \param node The root node of the skeleton tree that needs to be traversed.
	void apply(osg::Node& node)
	{
		// Look for the transformation root ..
		if (m_rootTransform == nullptr)
		{
			m_rootTransform = dynamic_cast<osg::MatrixTransform*>(&node);
		}

		// Parse the bone data.
		osgAnimation::Bone* bone = dynamic_cast<osgAnimation::Bone*>(&node);
		if (bone != nullptr)
		{
			SurgSim::Graphics::OsgSkeletonBoneData data;
			data.bone = bone;
			osgAnimation::UpdateMatrixTransform* callback =
				dynamic_cast<osgAnimation::UpdateMatrixTransform*>(bone->getUpdateCallback());

			// If we can't find this callback, replace with the default
			if (callback == nullptr)
			{
				bone->setDefaultUpdateCallback();
				callback = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(bone->getUpdateCallback());
			}

			SURGSIM_ASSERT(callback != nullptr) << "Could neither find nor create the appropriate BoneUpdate callback";

			// Push these transformations onto the stack so we can manipulate them
			data.rotation = new osgAnimation::StackedQuaternionElement("OssRotation");
			callback->getStackedTransforms().push_back(data.rotation);
			data.rotation->setQuaternion(osg::Quat());
			data.translation = new osgAnimation::StackedTranslateElement("OssTranslation");
			callback->getStackedTransforms().push_back(data.translation);

			SURGSIM_ASSERT(m_boneData.find(bone->getName()) == m_boneData.end())
				<< "There already exists a bone with name, " << bone->getName()
				<< ", in this skeleton. Cannot create a duplicate.";

			m_boneData[bone->getName()] = data;
		}

		// Setup for hardware skinning.
		if (m_shader != nullptr)
		{
			osg::Geode* meshGeode= dynamic_cast<osg::Geode*>(&node);
			if (nullptr != meshGeode)
			{
				osgAnimation::RigTransformHardware* rigTransform = new osgAnimation::RigTransformHardware();
				osg::Shader* shader = new osg::Shader(*m_shader);
				rigTransform->setShader(shader);

				for (size_t i = 0; i < meshGeode->getDrawableList().size(); ++i)
				{
					auto rigGeometry = dynamic_cast<osgAnimation::RigGeometry*>(meshGeode->getDrawable(i));
					if (nullptr != rigGeometry)
					{
						rigGeometry->setRigTransformImplementation(rigTransform);
					}
				}
			}
		}
		traverse(node);
	}

	/// \return The bone data that had been collected.
	std::map<std::string, SurgSim::Graphics::OsgSkeletonBoneData> getMap()
	{
		return m_boneData;
	}

	/// \return The root node of the skeleton on which the transform is set.
	osg::ref_ptr<osg::MatrixTransform> getRootTransform()
	{
		return m_rootTransform;
	}

private:
	/// The root bone of the skeleton where the global transform is set.
	osg::ref_ptr<osg::MatrixTransform> m_rootTransform;

	/// The hardware skinning shader.
	osg::ref_ptr<osg::Shader> m_shader;

	/// The bone data from the skeleton.
	std::map<std::string, SurgSim::Graphics::OsgSkeletonBoneData> m_boneData;
};

}

namespace SurgSim
{
namespace Graphics
{
SURGSIM_REGISTER(SurgSim::Framework::Component,
				 SurgSim::Graphics::OsgSkeletonRepresentation, OsgSkeletonRepresentation);

OsgSkeletonRepresentation::OsgSkeletonRepresentation(const std::string& name) :
	Representation(name),
	OsgRepresentation(name),
	SkeletonRepresentation(name)
{
	SURGSIM_ADD_SERIALIZABLE_PROPERTY(OsgSkeletonRepresentation, std::string,
		SkinningShaderFileName, getSkinningShaderFileName, setSkinningShaderFileName);
}

void OsgSkeletonRepresentation::loadModel(const std::string& fileName)
{
	SURGSIM_ASSERT(!isInitialized()) << "Cannot load model after OsgSkeletonRepresentation had been initialized.";

	auto model = std::make_shared<OsgModel>();
	model->load(fileName);
	setModel(model);
}

void OsgSkeletonRepresentation::setModel(std::shared_ptr<SurgSim::Framework::Asset> model)
{
	SURGSIM_ASSERT(!isInitialized()) << "Cannot set model after OsgSkeletonRepresentation had been initialized.";

	auto osgModel = std::dynamic_pointer_cast<OsgModel>(model);

	SURGSIM_ASSERT(model == nullptr || osgModel != nullptr) << "OsgSkeletonRepresentation expects an OsgModel.";

	m_model = osgModel;
}

std::shared_ptr<Model> OsgSkeletonRepresentation::getModel() const
{
	return m_model;
}

void OsgSkeletonRepresentation::setSkinningShaderFileName(std::string fileName)
{
	m_skinningShaderFileName = fileName;
}

std::string OsgSkeletonRepresentation::getSkinningShaderFileName()
{
	return m_skinningShaderFileName;
}

void OsgSkeletonRepresentation::setBonePose(const std::string& name, const SurgSim::Math::RigidTransform3d& pose)
{
	auto boneData = m_boneData.find(name);
	if (boneData != m_boneData.end())
	{
		boost::lock_guard<boost::mutex> lock(m_boneDataMutex);
		boneData->second.pose = pose;
	}
	else
	{
		SURGSIM_LOG_WARNING(SurgSim::Framework::Logger::getDefaultLogger())
			<< "OsgSkeletonRepresentation::setBonePose(): Bone with name, " << name << ", is not present in mesh."
			<< "Cannot set pose.";
	}
}

void OsgSkeletonRepresentation::doUpdate(double dt)
{
	{
		boost::lock_guard<boost::mutex> lock(m_boneDataMutex);
		// Update the pose of all the bones.
		for (auto& boneData : m_boneData)
		{
			std::pair<osg::Quat, osg::Vec3d> pose = toOsg(boneData.second.pose);
			boneData.second.rotation->setQuaternion(pose.first);
			boneData.second.translation->setTranslate(pose.second);
		}
	}

	// Update the position of the rest of the bones.
	m_base->accept(*m_updateVisitor);
	++m_frameCount;
	m_updateVisitor->setTraversalNumber(m_frameCount);
}

bool OsgSkeletonRepresentation::doInitialize()
{
	bool result = true;

	std::string shaderFilename;
	if (m_skinningShaderFileName.empty())
	{
		SURGSIM_LOG_SEVERE(SurgSim::Framework::Logger::getDefaultLogger())
			<< "OsgSkeletonRepresentation::doInitialize(): Skinning shader file not set.";
		result = false;
	}
	else
	{
		getRuntime()->getApplicationData()->tryFindFile(m_skinningShaderFileName, &shaderFilename);
	}

	if (result)
	{
		if (shaderFilename.empty())
		{
			SURGSIM_LOG_SEVERE(SurgSim::Framework::Logger::getDefaultLogger())
				<< "OsgSkeletonRepresentation::doInitialize(): Skinning shader file (" << m_skinningShaderFileName
				<< ") not found.";
			result = false;
		}
		else
		{
			m_skinningShader = new osg::Shader(osg::Shader::VERTEX);
			result = m_skinningShader->loadShaderSourceFromFile(shaderFilename);
		}
	}

	if (result)
	{
		if (m_model == nullptr || std::dynamic_pointer_cast<OsgModel>(m_model) == nullptr)
		{
			SURGSIM_LOG_SEVERE(SurgSim::Framework::Logger::getDefaultLogger())
				<< "OsgSkeletonRepresentation::doInitialize(): model is not set.";
			result = false;
		}
		else
		{
			m_skeleton = dynamic_cast<osg::Node*>(std::dynamic_pointer_cast<OsgModel>(m_model)->getOsgNode().get());
			result = nullptr != m_skeleton;
			SURGSIM_ASSERT(result)
				<< "OsgSkeletonRepresentation::doInitialize(): model does not have a valid osgNode.";
		}
	}

	if (result)
	{
		// Traverse the skeleton and collect bone data.
		BoneMapCreator mapCreator(m_skinningShader);
		mapCreator.traverse(*m_skeleton.get());
		m_boneData = mapCreator.getMap();
		if (m_boneData.size() == 0)
		{
			SURGSIM_LOG_SEVERE(SurgSim::Framework::Logger::getDefaultLogger())
				<< "Could not find any osgAnimation::Bone nodes in tree with root <" + m_skeleton->getName() + ">";
		}
		m_base = mapCreator.getRootTransform();

		// Setup the transform updater for the skeleton.
		m_updateVisitor = new osgUtil::UpdateVisitor();
		m_frameCount = 0;
		m_updateVisitor->setTraversalNumber(m_frameCount);
		m_base->accept(*m_updateVisitor);

		// Add the bone skeleton as a child to m_transform
		m_transform->addChild(m_base.get());
	}

	return result;
}

}; // Graphics
}; // SurgSim
<|endoftext|>


<commit_before>// @(#)root/thread:$Name:  $:$Id: TPosixThread.cxx,v 1.5 2003/08/06 21:31:24 rdm Exp $
// Author: Fons Rademakers   02/07/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPosixThread                                                         //
//                                                                      //
// This class provides an interface to the posix thread routines.       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TPosixThread.h"

ClassImp(TPosixThread)

//______________________________________________________________________________
Int_t TPosixThread::Run(TThread *th)
{
   int det;
   pthread_t id;
   pthread_attr_t *attr = new pthread_attr_t;

   pthread_attr_init(attr);

   // Set detach state
   det = (th->fDetached) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;

   pthread_attr_setdetachstate(attr, det);
   int ierr = pthread_create(&id, attr, &TThread::Fun, th);
   if (attr) pthread_attr_destroy(attr);
   return ierr;
}

//______________________________________________________________________________
Int_t TPosixThread::Join(Long_t jid, void **ret)
{
   return pthread_join((pthread_t) jid, ret);
}

//______________________________________________________________________________
Int_t TPosixThread::Exit(void *ret)
{
   pthread_exit(ret);
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::Kill(TThread *th)
{
   return pthread_cancel((pthread_t) th->fId);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOff()
{
   return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOn()
{
   return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelAsynchronous()
{
   return pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelDeferred()
{
   return pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::CancelPoint()
{
   int istate;
   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &istate );
   pthread_testcancel();
   pthread_setcancelstate(istate, 0);

   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUpPush(void **main, void *free,void *arg)
{
   // pthread_cleanup_push(free, arg);
   if (!free) fprintf(stderr, "CleanUpPush ***ERROR*** Routine=NULL\n");
   new TPosixThreadCleanUp(main,free,arg);
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUpPop(void **main,Int_t exe)
{
   //  pthread_cleanup_pop(exe); // happy pthread future

   if (!*main) return 1;
   TPosixThreadCleanUp *l = (TPosixThreadCleanUp*)(*main);
   if (!l->fRoutine) fprintf(stderr,"CleanUpPop ***ERROR*** Routine=NULL\n");
   if (exe && l->fRoutine) ((void (*)(void*))(l->fRoutine))(l->fArgument);
   *main = l->fNext;  delete l;
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUp(void **main)
{
   fprintf(stderr," CleanUp %lx\n",(Long_t)*main);
   while(!CleanUpPop(main,1)) { }
   return 0;
}

//______________________________________________________________________________
Long_t TPosixThread::SelfId()
{
   return (Long_t) pthread_self();
}

//______________________________________________________________________________
Int_t TPosixThread::Sleep(ULong_t secs, ULong_t /*nanos*/)
{
   return sleep(secs);
}

//______________________________________________________________________________
Int_t TPosixThread::GetTime(ULong_t * /*absSec*/, ULong_t * /*absNanoSec*/)
{
   return 0;
}

//   Clean Up section. PTHREAD implementations of cleanup after cancel are
//   too different and often too bad. Temporary I invent my own bicycle.
//                                                              V.Perev.

//______________________________________________________________________________
TPosixThreadCleanUp::TPosixThreadCleanUp(void **main, void *routine, void *arg)
{
   fNext = (TPosixThreadCleanUp*)*main;
   fRoutine = routine; fArgument = arg;
   *main  = this;
}
<commit_msg>From Bertrand: fix setting join id.<commit_after>// @(#)root/thread:$Name:  $:$Id: TPosixThread.cxx,v 1.6 2004/07/08 11:52:32 rdm Exp $
// Author: Fons Rademakers   02/07/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPosixThread                                                         //
//                                                                      //
// This class provides an interface to the posix thread routines.       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TPosixThread.h"

ClassImp(TPosixThread)

//______________________________________________________________________________
Int_t TPosixThread::Run(TThread *th)
{
   int det;
   pthread_t id;
   pthread_attr_t *attr = new pthread_attr_t;

   pthread_attr_init(attr);

   // Set detach state
   det = (th->fDetached) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;

   pthread_attr_setdetachstate(attr, det);
   int ierr = pthread_create(&id, attr, &TThread::Fun, th);
   if (attr) pthread_attr_destroy(attr);
   th->SetJoinId(id);
   return ierr;
}

//______________________________________________________________________________
Int_t TPosixThread::Join(Long_t jid, void **ret)
{
   return pthread_join((pthread_t) jid, ret);
}

//______________________________________________________________________________
Int_t TPosixThread::Exit(void *ret)
{
   pthread_exit(ret);
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::Kill(TThread *th)
{
   return pthread_cancel((pthread_t) th->fId);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOff()
{
   return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOn()
{
   return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelAsynchronous()
{
   return pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelDeferred()
{
   return pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::CancelPoint()
{
   int istate;
   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &istate );
   pthread_testcancel();
   pthread_setcancelstate(istate, 0);

   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUpPush(void **main, void *free,void *arg)
{
   // pthread_cleanup_push(free, arg);
   if (!free) fprintf(stderr, "CleanUpPush ***ERROR*** Routine=NULL\n");
   new TPosixThreadCleanUp(main,free,arg);
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUpPop(void **main,Int_t exe)
{
   //  pthread_cleanup_pop(exe); // happy pthread future

   if (!*main) return 1;
   TPosixThreadCleanUp *l = (TPosixThreadCleanUp*)(*main);
   if (!l->fRoutine) fprintf(stderr,"CleanUpPop ***ERROR*** Routine=NULL\n");
   if (exe && l->fRoutine) ((void (*)(void*))(l->fRoutine))(l->fArgument);
   *main = l->fNext;  delete l;
   return 0;
}

//______________________________________________________________________________
Int_t TPosixThread::CleanUp(void **main)
{
   fprintf(stderr," CleanUp %lx\n",(Long_t)*main);
   while(!CleanUpPop(main,1)) { }
   return 0;
}

//______________________________________________________________________________
Long_t TPosixThread::SelfId()
{
   return (Long_t) pthread_self();
}

//______________________________________________________________________________
Int_t TPosixThread::Sleep(ULong_t secs, ULong_t /*nanos*/)
{
   return sleep(secs);
}

//______________________________________________________________________________
Int_t TPosixThread::GetTime(ULong_t * /*absSec*/, ULong_t * /*absNanoSec*/)
{
   return 0;
}

//   Clean Up section. PTHREAD implementations of cleanup after cancel are
//   too different and often too bad. Temporary I invent my own bicycle.
//                                                              V.Perev.

//______________________________________________________________________________
TPosixThreadCleanUp::TPosixThreadCleanUp(void **main, void *routine, void *arg)
{
   fNext = (TPosixThreadCleanUp*)*main;
   fRoutine = routine; fArgument = arg;
   *main  = this;
}
<|endoftext|>