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