1 // Copyright (c) 2012 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 #include <string.h>
6 
7 #include <iostream>
8 #include <sstream>
9 
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/c/ppb_opengles2.h"
12 #include "ppapi/cpp/core.h"
13 #include "ppapi/cpp/fullscreen.h"
14 #include "ppapi/cpp/graphics_3d.h"
15 #include "ppapi/cpp/graphics_3d_client.h"
16 #include "ppapi/cpp/input_event.h"
17 #include "ppapi/cpp/instance.h"
18 #include "ppapi/cpp/module.h"
19 #include "ppapi/cpp/rect.h"
20 #include "ppapi/cpp/var.h"
21 #include "ppapi/lib/gl/include/GLES2/gl2.h"
22 #include "ppapi/utility/completion_callback_factory.h"
23 
24 // Use assert as a makeshift CHECK, even in non-debug mode.
25 // Since <assert.h> redefines assert on every inclusion (it doesn't use
26 // include-guards), make sure this is the last file #include'd in this file.
27 #undef NDEBUG
28 #include <assert.h>
29 #include <stdint.h>
30 
31 // Assert |context_| isn't holding any GL Errors.  Done as a macro instead of a
32 // function to preserve line number information in the failure message.
33 #define assertNoGLError() \
34   assert(!gles2_if_->GetError(context_->pp_resource()));
35 
36 namespace {
37 
38 class GLES2DemoInstance : public pp::Instance,
39                           public pp::Graphics3DClient {
40  public:
41   GLES2DemoInstance(PP_Instance instance, pp::Module* module);
42   virtual ~GLES2DemoInstance();
43 
44   // pp::Instance implementation (see PPP_Instance).
45   virtual void DidChangeView(const pp::Rect& position,
46                              const pp::Rect& clip_ignored);
47 
48   // pp::Graphics3DClient implementation.
Graphics3DContextLost()49   virtual void Graphics3DContextLost() {
50     // TODO(jamesr): What's the state of context_? Should we delete the old one
51     // or try to revive it somehow?
52     // For now, just delete it and construct+bind a new context.
53     delete context_;
54     context_ = NULL;
55     pp::CompletionCallback cb = callback_factory_.NewCallback(
56         &GLES2DemoInstance::InitGL);
57     module_->core()->CallOnMainThread(0, cb, 0);
58   }
59 
HandleInputEvent(const pp::InputEvent & event)60   virtual bool HandleInputEvent(const pp::InputEvent& event) {
61     if (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEUP) {
62       fullscreen_ = !fullscreen_;
63       pp::Fullscreen(this).SetFullscreen(fullscreen_);
64     }
65     return true;
66   }
67 
68  private:
69 
70   // GL-related functions.
71   void InitGL(int32_t result);
72   void FlickerAndPaint(int32_t result, bool paint_blue);
73 
74   pp::Size plugin_size_;
75   pp::CompletionCallbackFactory<GLES2DemoInstance> callback_factory_;
76 
77   // Unowned pointers.
78   const PPB_OpenGLES2* gles2_if_;
79   pp::Module* module_;
80 
81   // Owned data.
82   pp::Graphics3D* context_;
83   bool fullscreen_;
84 };
85 
GLES2DemoInstance(PP_Instance instance,pp::Module * module)86 GLES2DemoInstance::GLES2DemoInstance(PP_Instance instance, pp::Module* module)
87     : pp::Instance(instance), pp::Graphics3DClient(this),
88       callback_factory_(this),
89       gles2_if_(static_cast<const PPB_OpenGLES2*>(
90           module->GetBrowserInterface(PPB_OPENGLES2_INTERFACE))),
91       module_(module),
92       context_(NULL),
93       fullscreen_(false) {
94   assert(gles2_if_);
95   RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
96 }
97 
~GLES2DemoInstance()98 GLES2DemoInstance::~GLES2DemoInstance() {
99   delete context_;
100 }
101 
DidChangeView(const pp::Rect & position,const pp::Rect & clip_ignored)102 void GLES2DemoInstance::DidChangeView(
103     const pp::Rect& position, const pp::Rect& clip_ignored) {
104   if (position.width() == 0 || position.height() == 0)
105     return;
106   plugin_size_ = position.size();
107 
108   // Initialize graphics.
109   InitGL(0);
110 }
111 
112 // This object is the global object representing this plugin library as long
113 // as it is loaded.
114 class GLES2DemoModule : public pp::Module {
115  public:
GLES2DemoModule()116   GLES2DemoModule() : pp::Module() {}
~GLES2DemoModule()117   virtual ~GLES2DemoModule() {}
118 
CreateInstance(PP_Instance instance)119   virtual pp::Instance* CreateInstance(PP_Instance instance) {
120     return new GLES2DemoInstance(instance, this);
121   }
122 };
123 
InitGL(int32_t result)124 void GLES2DemoInstance::InitGL(int32_t result) {
125   assert(plugin_size_.width() && plugin_size_.height());
126 
127   if (context_) {
128     context_->ResizeBuffers(plugin_size_.width(), plugin_size_.height());
129     return;
130   }
131   int32_t context_attributes[] = {
132     PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
133     PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8,
134     PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
135     PP_GRAPHICS3DATTRIB_RED_SIZE, 8,
136     PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0,
137     PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0,
138     PP_GRAPHICS3DATTRIB_SAMPLES, 0,
139     PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
140     PP_GRAPHICS3DATTRIB_WIDTH, plugin_size_.width(),
141     PP_GRAPHICS3DATTRIB_HEIGHT, plugin_size_.height(),
142     PP_GRAPHICS3DATTRIB_NONE,
143   };
144   context_ = new pp::Graphics3D(this, context_attributes);
145   assert(!context_->is_null());
146   assert(BindGraphics(*context_));
147 
148   // Clear color bit.
149   gles2_if_->ClearColor(context_->pp_resource(), 0, 1, 0, 1);
150   gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT);
151 
152   assertNoGLError();
153 
154   FlickerAndPaint(0, true);
155 }
156 
FlickerAndPaint(int32_t result,bool paint_blue)157 void GLES2DemoInstance::FlickerAndPaint(int32_t result, bool paint_blue) {
158   if (result != 0 || !context_)
159     return;
160   float r = paint_blue ? 0 : 1.f;
161   float g = 0;
162   float b = paint_blue ? 1.f : 0;
163   float a = 0.75;
164   gles2_if_->ClearColor(context_->pp_resource(), r, g, b, a);
165   gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT);
166   assertNoGLError();
167 
168   pp::CompletionCallback cb = callback_factory_.NewCallback(
169       &GLES2DemoInstance::FlickerAndPaint, !paint_blue);
170   context_->SwapBuffers(cb);
171   assertNoGLError();
172 }
173 
174 }  // anonymous namespace
175 
176 namespace pp {
177 // Factory function for your specialization of the Module object.
CreateModule()178 Module* CreateModule() {
179   return new GLES2DemoModule();
180 }
181 }  // namespace pp
182