OLD | NEW |
| (Empty) |
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. | |
4 | |
5 // Needed on Windows to get |M_PI| from math.h. | |
6 #ifdef _WIN32 | |
7 #define _USE_MATH_DEFINES | |
8 #endif | |
9 | |
10 #include <math.h> | |
11 | |
12 #include <vector> | |
13 | |
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" | |
31 | |
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> | |
37 | |
38 // When compiling natively on Windows, PostMessage can be #define-d to | |
39 // something else. | |
40 #ifdef PostMessage | |
41 #undef PostMessage | |
42 #endif | |
43 | |
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()); | |
48 | |
49 namespace { | |
50 | |
51 const int32_t kTextureWidth = 800; | |
52 const int32_t kTextureHeight = 800; | |
53 const int32_t kImageWidth = 256; | |
54 const int32_t kImageHeight = 256; | |
55 | |
56 class DemoInstance : public pp::Instance, public pp::Graphics3DClient { | |
57 public: | |
58 DemoInstance(PP_Instance instance); | |
59 virtual ~DemoInstance(); | |
60 | |
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); | |
66 | |
67 // pp::Graphics3DClient implementation. | |
68 virtual void Graphics3DContextLost(); | |
69 | |
70 private: | |
71 // GL-related functions. | |
72 void InitGL(int32_t result); | |
73 GLuint PrepareFramebuffer(); | |
74 pp::ImageData PrepareImage(); | |
75 void Paint(int32_t result, int32_t frame); | |
76 void OnTextureReleased(int32_t result, GLuint texture); | |
77 void OnImageReleased(int32_t result, const pp::ImageData& image); | |
78 | |
79 pp::CompletionCallbackFactory<DemoInstance> callback_factory_; | |
80 | |
81 // Owned data. | |
82 pp::Graphics3D* context_; | |
83 | |
84 GLuint fbo_; | |
85 GLuint rbo_; | |
86 | |
87 std::vector<GLuint> textures_; | |
88 std::vector<pp::ImageData> images_; | |
89 | |
90 pp::Compositor compositor_; | |
91 pp::CompositorLayer color_layer_; | |
92 pp::CompositorLayer stable_texture_layer_; | |
93 pp::CompositorLayer texture_layer_; | |
94 pp::CompositorLayer image_layer_; | |
95 | |
96 bool rebuild_layers_; | |
97 int32_t total_resource_; | |
98 | |
99 SpinningCube* cube_; | |
100 }; | |
101 | |
102 DemoInstance::DemoInstance(PP_Instance instance) | |
103 : pp::Instance(instance), | |
104 pp::Graphics3DClient(this), | |
105 callback_factory_(this), | |
106 context_(NULL), | |
107 fbo_(0), | |
108 rbo_(0), | |
109 compositor_(this), | |
110 rebuild_layers_(false), | |
111 total_resource_(0), | |
112 cube_(new SpinningCube()) { | |
113 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); | |
114 } | |
115 | |
116 DemoInstance::~DemoInstance() { | |
117 delete cube_; | |
118 assert(glTerminatePPAPI()); | |
119 delete context_; | |
120 } | |
121 | |
122 bool DemoInstance::Init(uint32_t /*argc*/, | |
123 const char* /*argn*/[], | |
124 const char* /*argv*/[]) { | |
125 return !!glInitializePPAPI(pp::Module::Get()->get_browser_interface()); | |
126 } | |
127 | |
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); | |
134 } | |
135 | |
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; | |
143 } | |
144 return false; | |
145 } | |
146 | |
147 void DemoInstance::Graphics3DContextLost() { | |
148 fbo_ = 0; | |
149 rbo_ = 0; | |
150 compositor_.ResetLayers(); | |
151 color_layer_ = pp::CompositorLayer(); | |
152 stable_texture_layer_ = pp::CompositorLayer(); | |
153 texture_layer_ = pp::CompositorLayer(); | |
154 image_layer_ = pp::CompositorLayer(); | |
155 total_resource_ -= static_cast<int32_t>(textures_.size()); | |
156 textures_.clear(); | |
157 delete context_; | |
158 context_ = NULL; | |
159 cube_->OnGLContextLost(); | |
160 pp::CompletionCallback cb = callback_factory_.NewCallback( | |
161 &DemoInstance::InitGL); | |
162 pp::Module::Get()->core()->CallOnMainThread(0, cb, 0); | |
163 } | |
164 | |
165 void DemoInstance::InitGL(int32_t /*result*/) { | |
166 if (context_) | |
167 return; | |
168 int32_t context_attributes[] = { | |
169 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, | |
170 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, | |
171 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, | |
172 PP_GRAPHICS3DATTRIB_RED_SIZE, 8, | |
173 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, | |
174 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, | |
175 PP_GRAPHICS3DATTRIB_SAMPLES, 0, | |
176 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, | |
177 PP_GRAPHICS3DATTRIB_WIDTH, 32, | |
178 PP_GRAPHICS3DATTRIB_HEIGHT, 32, | |
179 PP_GRAPHICS3DATTRIB_NONE, | |
180 }; | |
181 context_ = new pp::Graphics3D(this, context_attributes); | |
182 assert(!context_->is_null()); | |
183 assert(BindGraphics(compositor_)); | |
184 | |
185 glSetCurrentContextPPAPI(context_->pp_resource()); | |
186 | |
187 cube_->Init(kTextureWidth, kTextureHeight); | |
188 | |
189 Paint(PP_OK, 0); | |
190 } | |
191 | |
192 GLuint DemoInstance::PrepareFramebuffer() { | |
193 GLuint texture = 0; | |
194 if (textures_.empty()) { | |
195 total_resource_++; | |
196 // Create a texture object | |
197 glGenTextures(1, &texture); | |
198 glBindTexture(GL_TEXTURE_2D, texture); | |
199 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureWidth, kTextureHeight, 0, | |
200 GL_RGBA, GL_UNSIGNED_BYTE, NULL); | |
201 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
202 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
203 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
204 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
205 glBindTexture(GL_TEXTURE_2D, 0); | |
206 } else { | |
207 texture = textures_.back(); | |
208 textures_.pop_back(); | |
209 } | |
210 | |
211 if (!rbo_) { | |
212 // create a renderbuffer object to store depth info | |
213 glGenRenderbuffers(1, &rbo_); | |
214 glBindRenderbuffer(GL_RENDERBUFFER, rbo_); | |
215 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, | |
216 kTextureWidth, kTextureHeight); | |
217 glBindRenderbuffer(GL_RENDERBUFFER, 0); | |
218 } | |
219 | |
220 if (!fbo_) { | |
221 // create a framebuffer object | |
222 glGenFramebuffers(1, &fbo_); | |
223 } | |
224 | |
225 glBindFramebuffer(GL_FRAMEBUFFER, fbo_); | |
226 | |
227 // attach the texture to FBO color attachment point | |
228 glFramebufferTexture2D(GL_FRAMEBUFFER, | |
229 GL_COLOR_ATTACHMENT0, | |
230 GL_TEXTURE_2D, | |
231 texture, | |
232 0); | |
233 | |
234 // attach the renderbuffer to depth attachment point | |
235 glFramebufferRenderbuffer(GL_FRAMEBUFFER, | |
236 GL_DEPTH_ATTACHMENT, | |
237 GL_RENDERBUFFER, | |
238 rbo_); | |
239 | |
240 // check FBO status | |
241 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); | |
242 assert(status == GL_FRAMEBUFFER_COMPLETE); | |
243 | |
244 AssertNoGLError(); | |
245 return texture; | |
246 } | |
247 | |
248 pp::ImageData DemoInstance::PrepareImage() { | |
249 if (images_.empty()) { | |
250 total_resource_++; | |
251 return pp::ImageData(this, | |
252 PP_IMAGEDATAFORMAT_RGBA_PREMUL, | |
253 pp::Size(kImageWidth, kImageHeight), | |
254 false); | |
255 } | |
256 pp::ImageData image = images_.back(); | |
257 images_.pop_back(); | |
258 return image; | |
259 } | |
260 | |
261 void DemoInstance::Paint(int32_t result, int32_t frame) { | |
262 assert(result == PP_OK); | |
263 | |
264 if (result != PP_OK || !context_) | |
265 return; | |
266 | |
267 int32_t rv; | |
268 | |
269 if (rebuild_layers_) { | |
270 compositor_.ResetLayers(); | |
271 color_layer_ = pp::CompositorLayer(); | |
272 stable_texture_layer_ = pp::CompositorLayer(); | |
273 texture_layer_ = pp::CompositorLayer(); | |
274 image_layer_ = pp::CompositorLayer(); | |
275 frame = 0; | |
276 rebuild_layers_ = false; | |
277 } | |
278 | |
279 float factor_sin = sin(M_PI / 180 * frame); | |
280 float factor_cos = cos(M_PI / 180 * frame); | |
281 { | |
282 // Set the background color layer. | |
283 if (color_layer_.is_null()) { | |
284 color_layer_ = compositor_.AddLayer(); | |
285 assert(!color_layer_.is_null()); | |
286 static const float transform[16] = { | |
287 1.0f, 0.0f, 0.0f, 0.0f, | |
288 0.0f, 1.0f, 0.0f, 0.0f, | |
289 0.0f, 0.0f, 1.0f, 0.0f, | |
290 0.0f, 0.0f, 0.0f, 1.0f, | |
291 }; | |
292 rv = color_layer_.SetTransform(transform); | |
293 assert(rv == PP_OK); | |
294 } | |
295 rv = color_layer_.SetColor(fabs(factor_sin), | |
296 fabs(factor_cos), | |
297 fabs(factor_sin * factor_cos), | |
298 1.0f, | |
299 pp::Size(800, 600)); | |
300 assert(rv == PP_OK); | |
301 } | |
302 | |
303 { | |
304 // Set the image layer | |
305 if (image_layer_.is_null()) { | |
306 image_layer_ = compositor_.AddLayer(); | |
307 assert(!image_layer_.is_null()); | |
308 } | |
309 float x = frame % 800; | |
310 float y = 200 - 200 * factor_sin; | |
311 const float transform[16] = { | |
312 fabs(factor_sin) + 0.2f, 0.0f, 0.0f, 0.0f, | |
313 0.0f, fabs(factor_sin) + 0.2f, 0.0f, 0.0f, | |
314 0.0f, 0.0f, 1.0f, 0.0f, | |
315 x, y, 0.0f, 1.0f, | |
316 }; | |
317 rv = image_layer_.SetTransform(transform); | |
318 assert(rv == PP_OK); | |
319 | |
320 pp::ImageData image = PrepareImage(); | |
321 uint8_t *p = static_cast<uint8_t*>(image.data()); | |
322 for (int x = 0; x < kImageWidth; ++x) { | |
323 for (int y = 0; y < kImageHeight; ++y) { | |
324 *(p++) = frame; | |
325 *(p++) = frame * x; | |
326 *(p++) = frame * y; | |
327 *(p++) = 255; | |
328 } | |
329 } | |
330 rv = image_layer_.SetImage(image, pp::Size(kImageWidth, kImageHeight), | |
331 callback_factory_.NewCallback(&DemoInstance::OnImageReleased, image)); | |
332 assert(rv == PP_OK_COMPLETIONPENDING); | |
333 } | |
334 | |
335 { | |
336 // Set the stable texture layer | |
337 if (stable_texture_layer_.is_null()) { | |
338 stable_texture_layer_ = compositor_.AddLayer(); | |
339 assert(!stable_texture_layer_.is_null()); | |
340 GLuint texture = PrepareFramebuffer(); | |
341 cube_->UpdateForTimeDelta(0.02f); | |
342 cube_->Draw(); | |
343 rv = stable_texture_layer_.SetTexture( | |
344 *context_, | |
345 texture, pp::Size(600, 600), | |
346 callback_factory_.NewCallback(&DemoInstance::OnTextureReleased, | |
347 texture)); | |
348 assert(rv == PP_OK_COMPLETIONPENDING); | |
349 rv = stable_texture_layer_.SetPremultipliedAlpha(PP_FALSE); | |
350 assert(rv == PP_OK); | |
351 } | |
352 | |
353 int32_t delta = 200 * fabsf(factor_sin); | |
354 if (delta != 0) { | |
355 int32_t x_y = 25 + delta; | |
356 int32_t w_h = 650 - delta - delta; | |
357 rv = stable_texture_layer_.SetClipRect(pp::Rect(x_y, x_y, w_h, w_h)); | |
358 } else { | |
359 rv = stable_texture_layer_.SetClipRect(pp::Rect()); | |
360 } | |
361 assert(rv == PP_OK); | |
362 | |
363 const float transform[16] = { | |
364 factor_cos, -factor_sin, 0.0f, 0.0f, | |
365 factor_sin, factor_cos, 0.0f, 0.0f, | |
366 0.0f, 0.0f, 1.0f, 0.0f, | |
367 50.0f, 50.0f, 0.0f, 1.0f, | |
368 }; | |
369 rv = stable_texture_layer_.SetTransform(transform); | |
370 assert(rv == PP_OK); | |
371 } | |
372 | |
373 { | |
374 // Set the dynamic texture layer. | |
375 if (texture_layer_.is_null()) { | |
376 texture_layer_ = compositor_.AddLayer(); | |
377 assert(!texture_layer_.is_null()); | |
378 static const float transform[16] = { | |
379 1.0f, 0.0f, 0.0f, 0.0f, | |
380 0.0f, 1.0f, 0.0f, 0.0f, | |
381 0.0f, 0.0f, 1.0f, 0.0f, | |
382 200.0f, 0.0f, 0.0f, 1.0f, | |
383 }; | |
384 rv = texture_layer_.SetTransform(transform); | |
385 assert(rv == PP_OK); | |
386 } | |
387 | |
388 GLuint texture = PrepareFramebuffer(); | |
389 cube_->UpdateForTimeDelta(0.02f); | |
390 cube_->Draw(); | |
391 rv = texture_layer_.SetTexture(*context_, texture, pp::Size(400, 400), | |
392 callback_factory_.NewCallback(&DemoInstance::OnTextureReleased, | |
393 texture)); | |
394 assert(rv == PP_OK_COMPLETIONPENDING); | |
395 rv = texture_layer_.SetPremultipliedAlpha(PP_FALSE); | |
396 assert(rv == PP_OK); | |
397 } | |
398 | |
399 rv = compositor_.CommitLayers( | |
400 callback_factory_.NewCallback(&DemoInstance::Paint, ++frame)); | |
401 assert(rv == PP_OK_COMPLETIONPENDING); | |
402 | |
403 pp::VarDictionary dict; | |
404 dict.Set(pp::Var("total_resource"), pp::Var(total_resource_)); | |
405 dict.Set(pp::Var("free_resource"), | |
406 pp::Var((int32_t)(textures_.size() + images_.size()))); | |
407 PostMessage(dict); | |
408 } | |
409 | |
410 void DemoInstance::OnTextureReleased(int32_t result, GLuint texture) { | |
411 if (result == PP_OK) | |
412 textures_.push_back(texture); | |
413 } | |
414 | |
415 void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) { | |
416 if (result == PP_OK) | |
417 images_.push_back(image); | |
418 } | |
419 | |
420 // This object is the global object representing this plugin library as long | |
421 // as it is loaded. | |
422 class DemoModule : public pp::Module { | |
423 public: | |
424 DemoModule() : Module() {} | |
425 virtual ~DemoModule() {} | |
426 | |
427 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
428 return new DemoInstance(instance); | |
429 } | |
430 }; | |
431 | |
432 } // anonymous namespace | |
433 | |
434 namespace pp { | |
435 // Factory function for your specialization of the Module object. | |
436 Module* CreateModule() { | |
437 return new DemoModule(); | |
438 } | |
439 } // namespace pp | |
OLD | NEW |