Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / ppapi / examples / compositor / compositor.cc
blobdf2962a9e14fb83ecef822f7fdc0cdd7acde5d5d
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Needed on Windows to get |M_PI| from math.h.
6 #ifdef _WIN32
7 #define _USE_MATH_DEFINES
8 #endif
10 #include <math.h>
12 #include <vector>
14 #include "ppapi/c/pp_errors.h"
15 #include "ppapi/c/pp_input_event.h"
16 #include "ppapi/cpp/compositor.h"
17 #include "ppapi/cpp/compositor_layer.h"
18 #include "ppapi/cpp/graphics_3d.h"
19 #include "ppapi/cpp/graphics_3d_client.h"
20 #include "ppapi/cpp/image_data.h"
21 #include "ppapi/cpp/input_event.h"
22 #include "ppapi/cpp/instance.h"
23 #include "ppapi/cpp/module.h"
24 #include "ppapi/cpp/rect.h"
25 #include "ppapi/cpp/var_dictionary.h"
26 #include "ppapi/examples/compositor/spinning_cube.h"
27 #include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
28 #include "ppapi/lib/gl/include/GLES2/gl2.h"
29 #include "ppapi/lib/gl/include/GLES2/gl2ext.h"
30 #include "ppapi/utility/completion_callback_factory.h"
32 // Use assert as a poor-man's CHECK, even in non-debug mode.
33 // Since <assert.h> redefines assert on every inclusion (it doesn't use
34 // include-guards), make sure this is the last file #include'd in this file.
35 #undef NDEBUG
36 #include <assert.h>
38 // When compiling natively on Windows, PostMessage can be #define-d to
39 // something else.
40 #ifdef PostMessage
41 #undef PostMessage
42 #endif
44 // Assert |context_| isn't holding any GL Errors. Done as a macro instead of a
45 // function to preserve line number information in the failure message.
46 #define AssertNoGLError() \
47 PP_DCHECK(!glGetError());
49 namespace {
51 const int32_t kTextureWidth = 800;
52 const int32_t kTextureHeight = 800;
53 const int32_t kImageWidth = 256;
54 const int32_t kImageHeight = 256;
56 class DemoInstance : public pp::Instance, public pp::Graphics3DClient {
57 public:
58 DemoInstance(PP_Instance instance);
59 virtual ~DemoInstance();
61 // pp::Instance implementation (see PPP_Instance).
62 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
63 virtual void DidChangeView(const pp::Rect& position,
64 const pp::Rect& clip);
65 virtual bool HandleInputEvent(const pp::InputEvent& event);
67 // pp::Graphics3DClient implementation.
68 virtual void Graphics3DContextLost();
70 private:
71 // GL-related functions.
72 void InitGL(int32_t result);
73 GLuint PrepareFramebuffer();
74 pp::ImageData PrepareImage();
75 void PrepareLayers(int32_t frame);
76 void Paint(int32_t result, int32_t frame);
77 void OnTextureReleased(int32_t result, GLuint texture);
78 void OnImageReleased(int32_t result, const pp::ImageData& image);
80 pp::CompletionCallbackFactory<DemoInstance> callback_factory_;
82 // Owned data.
83 pp::Graphics3D* context_;
85 GLuint fbo_;
86 GLuint rbo_;
88 std::vector<GLuint> textures_;
89 std::vector<pp::ImageData> images_;
91 pp::Compositor compositor_;
92 pp::CompositorLayer color_layer_;
93 pp::CompositorLayer stable_texture_layer_;
94 pp::CompositorLayer texture_layer_;
95 pp::CompositorLayer image_layer_;
97 bool rebuild_layers_;
98 int32_t total_resource_;
100 SpinningCube* cube_;
103 DemoInstance::DemoInstance(PP_Instance instance)
104 : pp::Instance(instance),
105 pp::Graphics3DClient(this),
106 callback_factory_(this),
107 context_(NULL),
108 fbo_(0),
109 rbo_(0),
110 rebuild_layers_(true),
111 total_resource_(0),
112 cube_(new SpinningCube()) {
113 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
116 DemoInstance::~DemoInstance() {
117 delete cube_;
118 assert(glTerminatePPAPI());
119 delete context_;
122 bool DemoInstance::Init(uint32_t /*argc*/,
123 const char* /*argn*/[],
124 const char* /*argv*/[]) {
125 return !!glInitializePPAPI(pp::Module::Get()->get_browser_interface());
128 void DemoInstance::DidChangeView(
129 const pp::Rect& position, const pp::Rect& /*clip*/) {
130 if (position.width() == 0 || position.height() == 0)
131 return;
132 // Initialize graphics.
133 InitGL(0);
136 bool DemoInstance::HandleInputEvent(const pp::InputEvent& event) {
137 switch (event.GetType()) {
138 case PP_INPUTEVENT_TYPE_MOUSEDOWN:
139 rebuild_layers_ = true;
140 return true;
141 default:
142 break;
144 return false;
147 void DemoInstance::Graphics3DContextLost() {
148 fbo_ = 0;
149 rbo_ = 0;
150 rebuild_layers_ = true;
151 total_resource_ -= static_cast<int32_t>(textures_.size());
152 textures_.clear();
153 delete context_;
154 context_ = NULL;
155 cube_->OnGLContextLost();
156 pp::CompletionCallback cb = callback_factory_.NewCallback(
157 &DemoInstance::InitGL);
158 pp::Module::Get()->core()->CallOnMainThread(0, cb, 0);
161 void DemoInstance::InitGL(int32_t /*result*/) {
162 if (context_)
163 return;
164 int32_t context_attributes[] = {
165 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
166 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8,
167 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
168 PP_GRAPHICS3DATTRIB_RED_SIZE, 8,
169 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0,
170 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0,
171 PP_GRAPHICS3DATTRIB_SAMPLES, 0,
172 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
173 PP_GRAPHICS3DATTRIB_WIDTH, 32,
174 PP_GRAPHICS3DATTRIB_HEIGHT, 32,
175 PP_GRAPHICS3DATTRIB_NONE,
177 context_ = new pp::Graphics3D(this, context_attributes);
178 assert(!context_->is_null());
179 assert(BindGraphics(compositor_));
181 glSetCurrentContextPPAPI(context_->pp_resource());
183 cube_->Init(kTextureWidth, kTextureHeight);
185 Paint(PP_OK, 0);
188 GLuint DemoInstance::PrepareFramebuffer() {
189 GLuint texture = 0;
190 if (textures_.empty()) {
191 total_resource_++;
192 // Create a texture object
193 glGenTextures(1, &texture);
194 glBindTexture(GL_TEXTURE_2D, texture);
195 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureWidth, kTextureHeight, 0,
196 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
197 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
198 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
199 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
200 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
201 glBindTexture(GL_TEXTURE_2D, 0);
202 } else {
203 texture = textures_.back();
204 textures_.pop_back();
207 if (!rbo_) {
208 // create a renderbuffer object to store depth info
209 glGenRenderbuffers(1, &rbo_);
210 glBindRenderbuffer(GL_RENDERBUFFER, rbo_);
211 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
212 kTextureWidth, kTextureHeight);
213 glBindRenderbuffer(GL_RENDERBUFFER, 0);
216 if (!fbo_) {
217 // create a framebuffer object
218 glGenFramebuffers(1, &fbo_);
221 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
223 // attach the texture to FBO color attachment point
224 glFramebufferTexture2D(GL_FRAMEBUFFER,
225 GL_COLOR_ATTACHMENT0,
226 GL_TEXTURE_2D,
227 texture,
230 // attach the renderbuffer to depth attachment point
231 glFramebufferRenderbuffer(GL_FRAMEBUFFER,
232 GL_DEPTH_ATTACHMENT,
233 GL_RENDERBUFFER,
234 rbo_);
236 // check FBO status
237 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
238 assert(status == GL_FRAMEBUFFER_COMPLETE);
240 AssertNoGLError();
241 return texture;
244 pp::ImageData DemoInstance::PrepareImage() {
245 if (images_.empty()) {
246 total_resource_++;
247 return pp::ImageData(this,
248 PP_IMAGEDATAFORMAT_RGBA_PREMUL,
249 pp::Size(kImageWidth, kImageHeight),
250 false);
252 pp::ImageData image = images_.back();
253 images_.pop_back();
254 return image;
257 void DemoInstance::Paint(int32_t result, int32_t frame) {
258 assert(result == PP_OK);
259 if (result != PP_OK || !context_)
260 return;
262 if (rebuild_layers_) {
263 compositor_ = pp::Compositor(this);
264 assert(BindGraphics(compositor_));
265 color_layer_ = pp::CompositorLayer();
266 stable_texture_layer_ = pp::CompositorLayer();
267 texture_layer_ = pp::CompositorLayer();
268 image_layer_ = pp::CompositorLayer();
269 frame = 0;
270 rebuild_layers_ = false;
273 PrepareLayers(frame);
275 int32_t rv = compositor_.CommitLayers(
276 callback_factory_.NewCallback(&DemoInstance::Paint, ++frame));
277 assert(rv == PP_OK_COMPLETIONPENDING);
279 pp::VarDictionary dict;
280 dict.Set("total_resource", total_resource_);
281 size_t free_resource = textures_.size() + images_.size();
282 dict.Set("free_resource", static_cast<int32_t>(free_resource));
283 PostMessage(dict);
286 void DemoInstance::PrepareLayers(int32_t frame) {
287 int32_t rv;
288 float factor_sin = sin(static_cast<float>(M_PI) / 180 * frame);
289 float factor_cos = cos(static_cast<float>(M_PI) / 180 * frame);
291 // Set the background color layer.
292 if (color_layer_.is_null()) {
293 color_layer_ = compositor_.AddLayer();
294 assert(!color_layer_.is_null());
295 static const float transform[16] = {
296 1.0f, 0.0f, 0.0f, 0.0f,
297 0.0f, 1.0f, 0.0f, 0.0f,
298 0.0f, 0.0f, 1.0f, 0.0f,
299 0.0f, 0.0f, 0.0f, 1.0f,
301 rv = color_layer_.SetTransform(transform);
302 assert(rv == PP_OK);
304 rv = color_layer_.SetColor(fabs(factor_sin),
305 fabs(factor_cos),
306 fabs(factor_sin * factor_cos),
307 1.0f,
308 pp::Size(800, 600));
309 assert(rv == PP_OK);
313 // Set the image layer
314 if (image_layer_.is_null()) {
315 image_layer_ = compositor_.AddLayer();
316 assert(!image_layer_.is_null());
318 float x = static_cast<float>(frame % 800);
319 float y = 200 - 200 * factor_sin;
320 const float transform[16] = {
321 fabsf(factor_sin) + 0.2f, 0.0f, 0.0f, 0.0f,
322 0.0f, fabsf(factor_sin) + 0.2f, 0.0f, 0.0f,
323 0.0f, 0.0f, 1.0f, 0.0f,
324 x, y, 0.0f, 1.0f,
326 rv = image_layer_.SetTransform(transform);
327 assert(rv == PP_OK);
329 pp::ImageData image = PrepareImage();
330 uint8_t *p = static_cast<uint8_t*>(image.data());
331 for (int x = 0; x < kImageWidth; ++x) {
332 for (int y = 0; y < kImageHeight; ++y) {
333 *(p++) = static_cast<uint8_t>(frame);
334 *(p++) = static_cast<uint8_t>(frame * x);
335 *(p++) = static_cast<uint8_t>(frame * y);
336 *(p++) = 255;
339 rv = image_layer_.SetImage(image, pp::Size(kImageWidth, kImageHeight),
340 callback_factory_.NewCallback(&DemoInstance::OnImageReleased, image));
341 assert(rv == PP_OK_COMPLETIONPENDING);
345 // Set the stable texture layer
346 if (stable_texture_layer_.is_null()) {
347 stable_texture_layer_ = compositor_.AddLayer();
348 assert(!stable_texture_layer_.is_null());
349 GLuint texture = PrepareFramebuffer();
350 cube_->UpdateForTimeDelta(0.02f);
351 cube_->Draw();
352 rv = stable_texture_layer_.SetTexture(
353 *context_,
354 GL_TEXTURE_2D,
355 texture,
356 pp::Size(600, 600),
357 callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
358 texture));
359 assert(rv == PP_OK_COMPLETIONPENDING);
360 rv = stable_texture_layer_.SetPremultipliedAlpha(PP_FALSE);
361 assert(rv == PP_OK);
364 int32_t delta = static_cast<int32_t>(200 * fabsf(factor_sin));
365 if (delta != 0) {
366 int32_t x_y = 25 + delta;
367 int32_t w_h = 650 - delta - delta;
368 rv = stable_texture_layer_.SetClipRect(pp::Rect(x_y, x_y, w_h, w_h));
369 } else {
370 rv = stable_texture_layer_.SetClipRect(pp::Rect());
372 assert(rv == PP_OK);
374 const float transform[16] = {
375 factor_cos, -factor_sin, 0.0f, 0.0f,
376 factor_sin, factor_cos, 0.0f, 0.0f,
377 0.0f, 0.0f, 1.0f, 0.0f,
378 50.0f, 50.0f, 0.0f, 1.0f,
380 rv = stable_texture_layer_.SetTransform(transform);
381 assert(rv == PP_OK);
385 // Set the dynamic texture layer.
386 if (texture_layer_.is_null()) {
387 texture_layer_ = compositor_.AddLayer();
388 assert(!texture_layer_.is_null());
389 static const float transform[16] = {
390 1.0f, 0.0f, 0.0f, 0.0f,
391 0.0f, 1.0f, 0.0f, 0.0f,
392 0.0f, 0.0f, 1.0f, 0.0f,
393 200.0f, 0.0f, 0.0f, 1.0f,
395 rv = texture_layer_.SetTransform(transform);
396 assert(rv == PP_OK);
399 GLuint texture = PrepareFramebuffer();
400 cube_->UpdateForTimeDelta(0.02f);
401 cube_->Draw();
402 rv = texture_layer_.SetTexture(
403 *context_,
404 GL_TEXTURE_2D,
405 texture,
406 pp::Size(400, 400),
407 callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
408 texture));
409 assert(rv == PP_OK_COMPLETIONPENDING);
410 rv = texture_layer_.SetPremultipliedAlpha(PP_FALSE);
411 assert(rv == PP_OK);
415 void DemoInstance::OnTextureReleased(int32_t result, GLuint texture) {
416 if (result == PP_OK) {
417 textures_.push_back(texture);
418 } else {
419 glDeleteTextures(1, &texture);
420 total_resource_--;
424 void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) {
425 if (result == PP_OK) {
426 images_.push_back(image);
427 } else {
428 total_resource_--;
432 // This object is the global object representing this plugin library as long
433 // as it is loaded.
434 class DemoModule : public pp::Module {
435 public:
436 DemoModule() : Module() {}
437 virtual ~DemoModule() {}
439 virtual pp::Instance* CreateInstance(PP_Instance instance) {
440 return new DemoInstance(instance);
444 } // anonymous namespace
446 namespace pp {
447 // Factory function for your specialization of the Module object.
448 Module* CreateModule() {
449 return new DemoModule();
451 } // namespace pp