1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <algorithm> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cassert> 10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/c/ppb_gamepad.h" 12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ppapi/cpp/graphics_2d.h" 13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ppapi/cpp/image_data.h" 14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ppapi/cpp/instance.h" 15b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ppapi/cpp/rect.h" 16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ppapi/cpp/size.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/var.h" 18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifdef WIN32 21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#undef min 22a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#undef max 23a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 24a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Allow 'this' in initializer list 25a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#pragma warning(disable : 4355) 26a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 27a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 28b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class GamepadInstance : public pp::Instance { 29b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) public: 30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) explicit GamepadInstance(PP_Instance instance); 31b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual ~GamepadInstance(); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Update the graphics context to the new size, and regenerate |pixel_buffer_| 34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // to fit the new size as well. 35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual void DidChangeView(const pp::View& view); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Flushes its contents of |pixel_buffer_| to the 2D graphics context. 38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void Paint(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int width() const { 41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return pixel_buffer_ ? pixel_buffer_->size().width() : 0; 42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int height() const { 44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return pixel_buffer_ ? pixel_buffer_->size().height() : 0; 45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Indicate whether a flush is pending. This can only be called from the 48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // main thread; it is not thread safe. 49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) bool flush_pending() const { return flush_pending_; } 50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void set_flush_pending(bool flag) { flush_pending_ = flag; } 51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 52b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) private: 53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Create and initialize the 2D context used for drawing. 54b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void CreateContext(const pp::Size& size); 55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Destroy the 2D drawing context. 56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void DestroyContext(); 57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Push the pixels to the browser, then attempt to flush the 2D context. If 58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // there is a pending flush on the 2D context, then update the pixels only 59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // and do not flush. 60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void FlushPixelBuffer(); 61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void FlushCallback(int32_t result); 63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) bool IsContextValid() const { return graphics_2d_context_ != NULL; } 65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pp::CompletionCallbackFactory<GamepadInstance> callback_factory_; 67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pp::Graphics2D* graphics_2d_context_; 68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pp::ImageData* pixel_buffer_; 69b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const PPB_Gamepad* gamepad_; 70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) bool flush_pending_; 71b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}; 72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GamepadInstance::GamepadInstance(PP_Instance instance) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : pp::Instance(instance), 75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) callback_factory_(this), 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) graphics_2d_context_(NULL), 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pixel_buffer_(NULL), 78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) flush_pending_(false) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pp::Module* module = pp::Module::Get(); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(module); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gamepad_ = static_cast<const PPB_Gamepad*>( 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) module->GetBrowserInterface(PPB_GAMEPAD_INTERFACE)); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(gamepad_); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GamepadInstance::~GamepadInstance() { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroyContext(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete pixel_buffer_; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GamepadInstance::DidChangeView(const pp::View& view) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pp::Rect position = view.GetRect(); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (position.size().width() == width() && 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) position.size().height() == height()) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Size didn't change, no need to update anything. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a new device context with the new size. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroyContext(); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateContext(position.size()); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete the old pixel buffer and create a new one. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete pixel_buffer_; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pixel_buffer_ = NULL; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (graphics_2d_context_ != NULL) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pixel_buffer_ = new pp::ImageData(this, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_IMAGEDATAFORMAT_BGRA_PREMUL, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) graphics_2d_context_->size(), 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Paint(); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void FillRect(pp::ImageData* image, 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int left, 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int top, 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int width, 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int height, 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t color) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int y = std::max(0, top); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y < std::min(image->size().height() - 1, top + height); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y++) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int x = std::max(0, left); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x < std::min(image->size().width() - 1, left + width); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x++) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *image->GetAddr32(pp::Point(x, y)) = color; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 128b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GamepadInstance::Paint() { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clear the background. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FillRect(pixel_buffer_, 0, 0, width(), height(), 0xfff0f0f0); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get current gamepad data. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_GamepadsSampleData gamepad_data; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gamepad_->Sample(pp_instance(), &gamepad_data); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the current state for each connected gamepad. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t p = 0; p < gamepad_data.length; ++p) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width2 = width() / gamepad_data.length / 2; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int height2 = height() / 2; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset = width2 * 2 * p; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_GamepadSampleData& pad = gamepad_data.items[p]; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!pad.connected) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw axes. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < pad.axes_length; i += 2) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = static_cast<int>(pad.axes[i + 0] * width2 + width2) + offset; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = static_cast<int>(pad.axes[i + 1] * height2 + height2); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t box_bgra = 0x80000000; // Alpha 50%. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FillRect(pixel_buffer_, x - 3, y - 3, 7, 7, box_bgra); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw buttons. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < pad.buttons_length; ++i) { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float button_val = pad.buttons[i]; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t colour = static_cast<uint32_t>((button_val * 192) + 63) << 24; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = i * 8 + 10 + offset; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = 10; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FillRect(pixel_buffer_, x - 3, y - 3, 7, 7, colour); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Output to the screen. 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FlushPixelBuffer(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 168b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GamepadInstance::CreateContext(const pp::Size& size) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsContextValid()) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) graphics_2d_context_ = new pp::Graphics2D(this, size, false); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!BindGraphics(*graphics_2d_context_)) { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("Couldn't bind the device context\n"); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 177b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GamepadInstance::DestroyContext() { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsContextValid()) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete graphics_2d_context_; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) graphics_2d_context_ = NULL; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 184b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GamepadInstance::FlushPixelBuffer() { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsContextValid()) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that the pixel lock is held while the buffer is copied into the 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // device context and then flushed. 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) graphics_2d_context_->PaintImageData(*pixel_buffer_, pp::Point()); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flush_pending()) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_flush_pending(true); 193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) graphics_2d_context_->Flush( 194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) callback_factory_.NewCallback(&GamepadInstance::FlushCallback)); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void GamepadInstance::FlushCallback(int32_t result) { 198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) set_flush_pending(false); 199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) Paint(); 200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class GamepadModule : public pp::Module { 203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) public: 204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) GamepadModule() : pp::Module() {} 205b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual ~GamepadModule() {} 206b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 207b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual pp::Instance* CreateInstance(PP_Instance instance) { 208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return new GamepadInstance(instance); 209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}; 211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace pp { 213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)Module* CreateModule() { return new GamepadModule(); } 214b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} // namespace pp 215