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.
7 #define _USE_MATH_DEFINES
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.
38 // When compiling natively on Windows, PostMessage can be #define-d to
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());
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 {
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();
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_;
83 pp::Graphics3D* context_;
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_;
98 int32_t total_resource_;
103 DemoInstance::DemoInstance(PP_Instance instance)
104 : pp::Instance(instance),
105 pp::Graphics3DClient(this),
106 callback_factory_(this),
110 rebuild_layers_(true),
112 cube_(new SpinningCube()) {
113 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
116 DemoInstance::~DemoInstance() {
118 assert(glTerminatePPAPI());
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)
132 // Initialize graphics.
136 bool DemoInstance::HandleInputEvent(const pp::InputEvent& event) {
137 switch (event.GetType()) {
138 case PP_INPUTEVENT_TYPE_MOUSEDOWN:
139 rebuild_layers_ = true;
147 void DemoInstance::Graphics3DContextLost() {
150 rebuild_layers_ = true;
151 total_resource_ -= static_cast<int32_t>(textures_.size());
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*/) {
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);
188 GLuint DemoInstance::PrepareFramebuffer() {
190 if (textures_.empty()) {
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);
203 texture = textures_.back();
204 textures_.pop_back();
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);
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,
230 // attach the renderbuffer to depth attachment point
231 glFramebufferRenderbuffer(GL_FRAMEBUFFER,
237 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
238 assert(status == GL_FRAMEBUFFER_COMPLETE);
244 pp::ImageData DemoInstance::PrepareImage() {
245 if (images_.empty()) {
247 return pp::ImageData(this,
248 PP_IMAGEDATAFORMAT_RGBA_PREMUL,
249 pp::Size(kImageWidth, kImageHeight),
252 pp::ImageData image = images_.back();
257 void DemoInstance::Paint(int32_t result, int32_t frame) {
258 assert(result == PP_OK);
259 if (result != PP_OK || !context_)
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();
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));
286 void DemoInstance::PrepareLayers(int32_t frame) {
288 float factor_sin = sin(M_PI / 180 * frame);
289 float factor_cos = cos(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);
304 rv = color_layer_.SetColor(fabs(factor_sin),
306 fabs(factor_sin * factor_cos),
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 = 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,
326 rv = image_layer_.SetTransform(transform);
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) {
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);
352 rv = stable_texture_layer_.SetTexture(
354 texture, pp::Size(600, 600),
355 callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
357 assert(rv == PP_OK_COMPLETIONPENDING);
358 rv = stable_texture_layer_.SetPremultipliedAlpha(PP_FALSE);
362 int32_t delta = 200 * fabsf(factor_sin);
364 int32_t x_y = 25 + delta;
365 int32_t w_h = 650 - delta - delta;
366 rv = stable_texture_layer_.SetClipRect(pp::Rect(x_y, x_y, w_h, w_h));
368 rv = stable_texture_layer_.SetClipRect(pp::Rect());
372 const float transform[16] = {
373 factor_cos, -factor_sin, 0.0f, 0.0f,
374 factor_sin, factor_cos, 0.0f, 0.0f,
375 0.0f, 0.0f, 1.0f, 0.0f,
376 50.0f, 50.0f, 0.0f, 1.0f,
378 rv = stable_texture_layer_.SetTransform(transform);
383 // Set the dynamic texture layer.
384 if (texture_layer_.is_null()) {
385 texture_layer_ = compositor_.AddLayer();
386 assert(!texture_layer_.is_null());
387 static const float transform[16] = {
388 1.0f, 0.0f, 0.0f, 0.0f,
389 0.0f, 1.0f, 0.0f, 0.0f,
390 0.0f, 0.0f, 1.0f, 0.0f,
391 200.0f, 0.0f, 0.0f, 1.0f,
393 rv = texture_layer_.SetTransform(transform);
397 GLuint texture = PrepareFramebuffer();
398 cube_->UpdateForTimeDelta(0.02f);
400 rv = texture_layer_.SetTexture(*context_, texture, pp::Size(400, 400),
401 callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
403 assert(rv == PP_OK_COMPLETIONPENDING);
404 rv = texture_layer_.SetPremultipliedAlpha(PP_FALSE);
409 void DemoInstance::OnTextureReleased(int32_t result, GLuint texture) {
410 if (result == PP_OK) {
411 textures_.push_back(texture);
413 glDeleteTextures(1, &texture);
418 void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) {
419 if (result == PP_OK) {
420 images_.push_back(image);
426 // This object is the global object representing this plugin library as long
428 class DemoModule : public pp::Module {
430 DemoModule() : Module() {}
431 virtual ~DemoModule() {}
433 virtual pp::Instance* CreateInstance(PP_Instance instance) {
434 return new DemoInstance(instance);
438 } // anonymous namespace
441 // Factory function for your specialization of the Module object.
442 Module* CreateModule() {
443 return new DemoModule();