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(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
);
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
= 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
,
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
) {
333 *(p
++) = static_cast<uint8_t>(frame
);
334 *(p
++) = static_cast<uint8_t>(frame
* x
);
335 *(p
++) = static_cast<uint8_t>(frame
* 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(
357 callback_factory_
.NewCallback(&DemoInstance::OnTextureReleased
,
359 assert(rv
== PP_OK_COMPLETIONPENDING
);
360 rv
= stable_texture_layer_
.SetPremultipliedAlpha(PP_FALSE
);
364 int32_t delta
= static_cast<int32_t>(200 * fabsf(factor_sin
));
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
));
370 rv
= stable_texture_layer_
.SetClipRect(pp::Rect());
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
);
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
);
399 GLuint texture
= PrepareFramebuffer();
400 cube_
->UpdateForTimeDelta(0.02f
);
402 rv
= texture_layer_
.SetTexture(
407 callback_factory_
.NewCallback(&DemoInstance::OnTextureReleased
,
409 assert(rv
== PP_OK_COMPLETIONPENDING
);
410 rv
= texture_layer_
.SetPremultipliedAlpha(PP_FALSE
);
415 void DemoInstance::OnTextureReleased(int32_t result
, GLuint texture
) {
416 if (result
== PP_OK
) {
417 textures_
.push_back(texture
);
419 glDeleteTextures(1, &texture
);
424 void DemoInstance::OnImageReleased(int32_t result
, const pp::ImageData
& image
) {
425 if (result
== PP_OK
) {
426 images_
.push_back(image
);
432 // This object is the global object representing this plugin library as long
434 class DemoModule
: public pp::Module
{
436 DemoModule() : Module() {}
437 virtual ~DemoModule() {}
439 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
440 return new DemoInstance(instance
);
444 } // anonymous namespace
447 // Factory function for your specialization of the Module object.
448 Module
* CreateModule() {
449 return new DemoModule();