137 lines
4.4 KiB
C++

// 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 "tumbler.h"
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include "cube.h"
#include "opengl_context.h"
#include "scripting_bridge.h"
#include "ppapi/cpp/rect.h"
#include "ppapi/cpp/size.h"
#include "ppapi/cpp/var.h"
namespace {
const size_t kQuaternionElementCount = 4;
const char* const kArrayStartCharacter = "[";
const char* const kArrayEndCharacter = "]";
const char* const kArrayDelimiter = ",";
// Return the value of parameter named |param_name| from |parameters|. If
// |param_name| doesn't exist, then return an empty string.
std::string GetParameterNamed(
const std::string& param_name,
const tumbler::MethodParameter& parameters) {
tumbler::MethodParameter::const_iterator i =
parameters.find(param_name);
if (i == parameters.end()) {
return "";
}
return i->second;
}
// Convert the JSON string |array| into a vector of floats. |array| is
// expected to be a string bounded by '[' and ']', and a comma-delimited list
// of numbers. Any errors result in the return of an empty array.
std::vector<float> CreateArrayFromJSON(const std::string& json_array) {
std::vector<float> float_array;
size_t array_start_pos = json_array.find_first_of(kArrayStartCharacter);
size_t array_end_pos = json_array.find_last_of(kArrayEndCharacter);
if (array_start_pos == std::string::npos ||
array_end_pos == std::string::npos)
return float_array; // Malformed JSON: missing '[' or ']'.
// Pull out the array elements.
size_t token_pos = array_start_pos + 1;
while (token_pos < array_end_pos) {
float_array.push_back(strtof(json_array.data() + token_pos, NULL));
size_t delim_pos = json_array.find_first_of(kArrayDelimiter, token_pos);
if (delim_pos == std::string::npos)
break;
token_pos = delim_pos + 1;
}
return float_array;
}
} // namespace
namespace tumbler {
Tumbler::Tumbler(PP_Instance instance)
: pp::Instance(instance),
cube_(NULL) {
}
Tumbler::~Tumbler() {
// Destroy the cube view while GL context is current.
opengl_context_->MakeContextCurrent(this);
delete cube_;
}
bool Tumbler::Init(uint32_t /* argc */,
const char* /* argn */[],
const char* /* argv */[]) {
// Add all the methods to the scripting bridge.
ScriptingBridge::SharedMethodCallbackExecutor set_orientation_method(
new tumbler::MethodCallback<Tumbler>(
this, &Tumbler::SetCameraOrientation));
scripting_bridge_.AddMethodNamed("setCameraOrientation",
set_orientation_method);
return true;
}
void Tumbler::HandleMessage(const pp::Var& message) {
if (!message.is_string())
return;
scripting_bridge_.InvokeMethod(message.AsString());
}
void Tumbler::DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
int cube_width = cube_ ? cube_->width() : 0;
int cube_height = cube_ ? cube_->height() : 0;
if (position.size().width() == cube_width &&
position.size().height() == cube_height)
return; // Size didn't change, no need to update anything.
if (opengl_context_ == NULL)
opengl_context_.reset(new OpenGLContext(this));
opengl_context_->InvalidateContext(this);
if (!opengl_context_->MakeContextCurrent(this))
return;
if (cube_ == NULL) {
cube_ = new Cube(opengl_context_);
cube_->PrepareOpenGL();
}
cube_->Resize(position.size().width(), position.size().height());
DrawSelf();
}
void Tumbler::DrawSelf() {
if (cube_ == NULL || opengl_context_ == NULL)
return;
opengl_context_->MakeContextCurrent(this);
cube_->Draw();
opengl_context_->FlushContext();
}
void Tumbler::SetCameraOrientation(
const tumbler::ScriptingBridge& bridge,
const tumbler::MethodParameter& parameters) {
// |parameters| is expected to contain one object named "orientation", whose
// value is a JSON string that represents an array of four floats.
if (parameters.size() != 1 || cube_ == NULL)
return;
std::string orientation_desc = GetParameterNamed("orientation", parameters);
std::vector<float> orientation = CreateArrayFromJSON(orientation_desc);
if (orientation.size() != kQuaternionElementCount) {
return;
}
cube_->SetOrientation(orientation);
DrawSelf();
}
} // namespace tumbler