Index: ppapi/examples/compositor/compositor.cc |
diff --git a/ppapi/examples/compositor/compositor.cc b/ppapi/examples/compositor/compositor.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..98ecac43b43d3a6db582b7caa3966651be7b59f1 |
--- /dev/null |
+++ b/ppapi/examples/compositor/compositor.cc |
@@ -0,0 +1,363 @@ |
+// 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 <math.h> |
+#include <stdio.h> |
+ |
+#include <vector> |
+ |
+#include "ppapi/c/pp_errors.h" |
+#include "ppapi/cpp/compositor.h" |
+#include "ppapi/cpp/compositor_layer.h" |
+#include "ppapi/cpp/core.h" |
+#include "ppapi/cpp/graphics_3d.h" |
+#include "ppapi/cpp/graphics_3d_client.h" |
+#include "ppapi/cpp/image_data.h" |
+#include "ppapi/cpp/instance.h" |
+#include "ppapi/cpp/module.h" |
+#include "ppapi/cpp/rect.h" |
+#include "ppapi/examples/compositor/spinning_cube.h" |
+#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h" |
+#include "ppapi/lib/gl/include/GLES2/gl2.h" |
+#include "ppapi/lib/gl/include/GLES2/gl2ext.h" |
+#include "ppapi/utility/completion_callback_factory.h" |
+ |
+// Use assert as a poor-man's CHECK, even in non-debug mode. |
+// Since <assert.h> redefines assert on every inclusion (it doesn't use |
+// include-guards), make sure this is the last file #include'd in this file. |
+#undef NDEBUG |
+#include <assert.h> |
+ |
+namespace { |
+ |
+const int32_t kTextureWidth = 800; |
+const int32_t kTextureHeight = 800; |
+const int32_t kImageWidth = 256; |
+const int32_t kImageHeight = 256; |
+ |
+class DemoInstance : public pp::Instance, public pp::Graphics3DClient { |
+ public: |
+ DemoInstance(PP_Instance instance); |
+ virtual ~DemoInstance(); |
+ |
+ // pp::Instance implementation (see PPP_Instance). |
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); |
+ virtual void DidChangeView(const pp::Rect& position, |
+ const pp::Rect& clip); |
+ |
+ // pp::Graphics3DClient implementation. |
+ virtual void Graphics3DContextLost(); |
+ |
+ private: |
+ // GL-related functions. |
+ void InitGL(int32_t result); |
+ GLuint PrepareFramebuffer(); |
+ pp::ImageData PrepareImage(); |
+ void Paint(int32_t result); |
+ void OnTextureReleased(int32_t result, GLuint texture); |
+ void OnImageReleased(int32_t result, const pp::ImageData& image); |
+ |
+ pp::Size plugin_size_; |
+ pp::CompletionCallbackFactory<DemoInstance> callback_factory_; |
+ |
+ // Owned data. |
+ pp::Graphics3D* context_; |
+ |
+ GLuint fbo_; |
+ GLuint rbo_; |
+ |
+ std::vector<GLuint> textures_; |
+ std::vector<pp::ImageData> images_; |
+ |
+ pp::Compositor compositor_; |
+ |
+ pp::CompositorLayer color_layer_; |
+ pp::CompositorLayer stable_texture_layer_; |
+ pp::CompositorLayer texture_layer_; |
+ pp::CompositorLayer image_layer_; |
+ uint32_t frame_; |
+ |
+ SpinningCube* cube_; |
+}; |
+ |
+DemoInstance::DemoInstance(PP_Instance instance) |
+ : pp::Instance(instance), |
+ pp::Graphics3DClient(this), |
+ callback_factory_(this), |
+ context_(NULL), |
+ fbo_(0), |
+ rbo_(0), |
+ compositor_(this), |
+ frame_(0), |
+ cube_(new SpinningCube()) {} |
+ |
+DemoInstance::~DemoInstance() { |
+ delete cube_; |
+ assert(glTerminatePPAPI()); |
+ delete context_; |
+} |
+ |
+bool DemoInstance::Init(uint32_t /*argc*/, |
+ const char* /*argn*/[], |
+ const char* /*argv*/[]) { |
+ return !!glInitializePPAPI(pp::Module::Get()->get_browser_interface()); |
+} |
+ |
+void DemoInstance::DidChangeView( |
+ const pp::Rect& position, const pp::Rect& /*clip*/) { |
+ if (position.width() == 0 || position.height() == 0) |
+ return; |
+ plugin_size_ = position.size(); |
+ |
+ // Initialize graphics. |
+ InitGL(0); |
+} |
+ |
+void DemoInstance::Graphics3DContextLost() { |
+ fbo_ = 0; |
+ rbo_ = 0; |
+ compositor_.ResetLayers(); |
+ color_layer_ = pp::CompositorLayer(); |
+ stable_texture_layer_ = pp::CompositorLayer(); |
+ texture_layer_ = pp::CompositorLayer(); |
+ image_layer_ = pp::CompositorLayer(); |
+ textures_.clear(); |
+ delete context_; |
+ context_ = NULL; |
+ cube_->OnGLContextLost(); |
+ pp::CompletionCallback cb = callback_factory_.NewCallback( |
+ &DemoInstance::InitGL); |
+ pp::Module::Get()->core()->CallOnMainThread(0, cb, 0); |
+} |
+ |
+void DemoInstance::InitGL(int32_t /*result*/) { |
+ assert(plugin_size_.width() && plugin_size_.height()); |
+ |
+ if (context_) { |
+ context_->ResizeBuffers(plugin_size_.width(), plugin_size_.height()); |
+ return; |
+ } |
+ int32_t context_attributes[] = { |
+ PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, |
+ PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, |
+ PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, |
+ PP_GRAPHICS3DATTRIB_RED_SIZE, 8, |
+ PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, |
+ PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, |
+ PP_GRAPHICS3DATTRIB_SAMPLES, 0, |
+ PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, |
+ PP_GRAPHICS3DATTRIB_WIDTH, plugin_size_.width(), |
+ PP_GRAPHICS3DATTRIB_HEIGHT, plugin_size_.height(), |
+ PP_GRAPHICS3DATTRIB_NONE, |
+ }; |
+ context_ = new pp::Graphics3D(this, context_attributes); |
+ assert(!context_->is_null()); |
+ assert(BindGraphics(compositor_)); |
+ |
+ glSetCurrentContextPPAPI(context_->pp_resource()); |
+ |
+ cube_->Init(kTextureWidth, kTextureHeight); |
+ |
+ Paint(PP_OK); |
+} |
+ |
+GLuint DemoInstance::PrepareFramebuffer() { |
+ GLuint texture = 0; |
+ if (textures_.empty()) { |
+ // Create a texture object |
+ glGenTextures(1, &texture); |
+ glBindTexture(GL_TEXTURE_2D, texture); |
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureWidth, kTextureHeight, 0, |
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL); |
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
+ // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
+ // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
+ glBindTexture(GL_TEXTURE_2D, 0); |
+ } else { |
+ texture = textures_.back(); |
+ textures_.pop_back(); |
+ } |
+ |
+ if (!rbo_) { |
+ // create a renderbuffer object to store depth info |
+ glGenRenderbuffers(1, &rbo_); |
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo_); |
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, |
+ kTextureWidth, kTextureHeight); |
+ glBindRenderbuffer(GL_RENDERBUFFER, 0); |
+ } |
+ |
+ if (!fbo_) { |
+ // create a framebuffer object |
+ glGenFramebuffers(1, &fbo_); |
+ } |
+ |
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
+ |
+ // attach the texture to FBO color attachment point |
+ glFramebufferTexture2D(GL_FRAMEBUFFER, |
+ GL_COLOR_ATTACHMENT0, |
+ GL_TEXTURE_2D, |
+ texture, |
+ 0); |
+ |
+ // attach the renderbuffer to depth attachment point |
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, |
+ GL_DEPTH_ATTACHMENT, |
+ GL_RENDERBUFFER, |
+ rbo_); |
+ |
+ // check FBO status |
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |
+ assert(status == GL_FRAMEBUFFER_COMPLETE); |
+ |
+ return texture; |
+} |
+ |
+pp::ImageData DemoInstance::PrepareImage() { |
+ if (images_.empty()) { |
+ return pp::ImageData(this, |
+ PP_IMAGEDATAFORMAT_RGBA_PREMUL, |
+ pp::Size(kImageWidth, kImageHeight), false); |
+ } |
+ pp::ImageData image = images_.back(); |
+ images_.pop_back(); |
+ return image; |
+} |
+ |
+void DemoInstance::Paint(int32_t result) { |
+ if (result != PP_OK || !context_) |
+ return; |
+ float factor_sin = sin(M_PI / 180 * frame_); |
+ float factor_cos = cos(M_PI / 180 * frame_); |
+ { |
+ // Set the background color layer. |
+ if (color_layer_.is_null()) { |
+ color_layer_ = compositor_.AddLayer(); |
+ assert(!color_layer_.is_null()); |
+ static const float transform[16] = { |
+ 1.0f, 0.0f, 0.0f, 0.0f, |
+ 0.0f, 1.0f, 0.0f, 0.0f, |
+ 0.0f, 0.0f, 1.0f, 0.0f, |
+ 0.0f, 0.0f, 0.0f, 1.0f, |
+ }; |
+ color_layer_.SetTransform(transform); |
+ } |
+ color_layer_.SetColor(255 * factor_sin, |
+ 255 * factor_cos, |
+ 255 * factor_sin * factor_cos, |
+ 255, |
+ pp::Size(800, 600)); |
+ } |
+ |
+ { |
+ // Set the image layer |
+ if (image_layer_.is_null()) { |
+ image_layer_ = compositor_.AddLayer(); |
+ assert(!image_layer_.is_null()); |
+ } |
+ float x = frame_ % 800; |
+ float y = 200 - 200 * factor_sin; |
+ const float transform[16] = { |
+ fabsf(factor_sin) + 0.2f, 0.0f, 0.0f, 0.0f, |
+ 0.0f, fabsf(factor_sin) + 0.2f, 0.0f, 0.0f, |
+ 0.0f, 0.0f, 1.0f, 0.0f, |
+ x, y, 0.0f, 1.0f, |
+ }; |
+ image_layer_.SetTransform(transform); |
+ pp::ImageData image = PrepareImage(); |
+ uint8_t *p = static_cast<uint8_t*>(image.data()); |
+ for (int x = 0; x < kImageWidth; x++) { |
+ for (int y = 0; y < kImageHeight; y++) { |
+ *(p++) = frame_; |
+ *(p++) = frame_ * x; |
+ *(p++) = frame_ * y; |
+ *(p++) = 255; |
+ } |
+ } |
+ image_layer_.SetImage(image, pp::Size(kImageWidth, kImageHeight), |
+ callback_factory_.NewCallback(&DemoInstance::OnImageReleased, image)); |
+ } |
+ |
+ { |
+ // Set the stable texture layer |
+ if (stable_texture_layer_.is_null()) { |
+ stable_texture_layer_ = compositor_.AddLayer(); |
+ assert(!stable_texture_layer_.is_null()); |
+ stable_texture_layer_.SetPremultipliedAlpha(PP_FALSE); |
+ // stable_texture_layer_.SetClipRect(pp::Rect(50, 50, 400, 400)); |
+ GLuint texture = PrepareFramebuffer(); |
+ cube_->UpdateForTimeDelta(0.02f); |
+ cube_->Draw(); |
+ stable_texture_layer_.SetTexture(*context_, texture, pp::Size(600, 600), |
+ callback_factory_.NewCallback(&DemoInstance::OnTextureReleased, |
+ texture)); |
+ } |
+ float x = 10 - 100 * factor_sin; |
+ float y = 10 - 100 * factor_cos; |
+ const float transform[16] = { |
+ 1.0f, 0.0f, 0.0f, 0.0f, |
+ 0.0f, 1.0f, 0.0f, 0.0f, |
+ 0.0f, 0.0f, 1.0f, 0.0f, |
+ x, y, 0.0f, 1.0f, |
+ }; |
+ stable_texture_layer_.SetTransform(transform); |
+ } |
+ |
+ |
+ if (texture_layer_.is_null()) { |
+ texture_layer_ = compositor_.AddLayer(); |
+ assert(!texture_layer_.is_null()); |
+ static const float transform[16] = { |
+ 1.0f, 0.0f, 0.0f, 0.0f, |
+ 0.0f, 1.0f, 0.0f, 0.0f, |
+ 0.0f, 0.0f, 1.0f, 0.0f, |
+ 200.0f, 0.0f, 0.0f, 1.0f, |
+ }; |
+ texture_layer_.SetTransform(transform); |
+ texture_layer_.SetPremultipliedAlpha(PP_FALSE); |
+ } |
+ |
+ GLuint texture = PrepareFramebuffer(); |
+ cube_->UpdateForTimeDelta(0.02f); |
+ cube_->Draw(); |
+ texture_layer_.SetTexture(*context_, texture, pp::Size(400, 400), |
+ callback_factory_.NewCallback(&DemoInstance::OnTextureReleased, texture)); |
+ |
+ compositor_.CommitLayers( |
+ callback_factory_.NewCallback(&DemoInstance::Paint)); |
+ ++frame_; |
+} |
+ |
+void DemoInstance::OnTextureReleased(int32_t result, GLuint texture) { |
+ if (result == PP_OK) |
+ textures_.push_back(texture); |
+} |
+ |
+void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) { |
+ if (result == PP_OK); |
+ images_.push_back(image); |
+} |
+ |
+// This object is the global object representing this plugin library as long |
+// as it is loaded. |
+class DemoModule : public pp::Module { |
+ public: |
+ DemoModule() : Module() {} |
+ virtual ~DemoModule() {} |
+ |
+ virtual pp::Instance* CreateInstance(PP_Instance instance) { |
+ return new DemoInstance(instance); |
+ } |
+}; |
+ |
+} // anonymous namespace |
+ |
+namespace pp { |
+// Factory function for your specialization of the Module object. |
+Module* CreateModule() { |
+ return new DemoModule(); |
+} |
+} // namespace pp |