summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorscottmg@chromium.org <scottmg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-19 19:35:20 +0000
committerscottmg@chromium.org <scottmg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-19 19:35:20 +0000
commit5efe44c3aefe5ca73a9c3edbdaf0cf51ba72294a (patch)
treeb81c8ba11ef6fe41a5e7840f6ba8e6f009e86e56 /native_client_sdk
parent7f2c1921a1b70eeaf3e62c25dc6f72b308259080 (diff)
downloadchromium_src-5efe44c3aefe5ca73a9c3edbdaf0cf51ba72294a.zip
chromium_src-5efe44c3aefe5ca73a9c3edbdaf0cf51ba72294a.tar.gz
chromium_src-5efe44c3aefe5ca73a9c3edbdaf0cf51ba72294a.tar.bz2
Add simple NaCl gamepad example
BUG=79098 Review URL: http://codereview.chromium.org/9148086 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118334 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/examples/gamepad/Makefile183
-rw-r--r--native_client_sdk/src/examples/gamepad/gamepad.cc149
-rw-r--r--native_client_sdk/src/examples/gamepad/gamepad.h80
-rw-r--r--native_client_sdk/src/examples/gamepad/gamepad.html24
-rw-r--r--native_client_sdk/src/examples/gamepad/gamepad.nmf6
-rw-r--r--native_client_sdk/src/examples/gamepad/gamepad_module.cc34
6 files changed, 476 insertions, 0 deletions
diff --git a/native_client_sdk/src/examples/gamepad/Makefile b/native_client_sdk/src/examples/gamepad/Makefile
new file mode 100644
index 0000000..f1a69f1
--- /dev/null
+++ b/native_client_sdk/src/examples/gamepad/Makefile
@@ -0,0 +1,183 @@
+# Copyright (c) 2012 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+#
+# GNU Make based build file.  For details on GNU Make see:
+#   http://www.gnu.org/software/make/manual/make.html
+#
+
+#
+# Project information
+#
+# These variables store project specific settings for the project name
+# build flags, files to copy or install.  In the examples it is typically
+# only the list of sources and project name that will actually change and
+# the rest of the makefile is boilerplate for defining build rules.
+#
+PROJECT:=gamepad
+CXX_SOURCES:=gamepad.cc gamepad_module.cc
+COPY_FILES:=gamepad.html gamepad.nmf
+LDFLAGS:=-lppapi_cpp -lppapi
+
+
+#
+# Get pepper directory for toolchain and includes.
+#
+# If PEPPER_ROOT is not set, then assume it can be found a two directories up,
+# from the default example directory location.
+#
+THIS_MAKEFILE:=$(abspath $(lastword $(MAKEFILE_LIST)))
+PEPPER_ROOT?=$(abspath $(dir $(THIS_MAKEFILE))../..)
+
+# Project Build flags
+DEFINES:=
+INCLUDES:=
+WARNINGS:=-Wno-long-long -Wall -Wswitch-enum -pedantic -Werror
+CXXFLAGS:=-pthread -std=gnu++98 $(WARNINGS) $(DEFINES) $(INCLUDES)
+
+#
+# Compute tool paths
+#
+#
+OSNAME:=$(shell python $(PEPPER_ROOT)/tools/getos.py)
+TC_PATH:=$(abspath $(PEPPER_ROOT)/toolchain/$(OSNAME)_x86_newlib)
+CC:=$(TC_PATH)/bin/i686-nacl-gcc
+CXX:=$(TC_PATH)/bin/i686-nacl-g++
+STRIP:=$(TC_PATH)/bin/i686-nacl-strip
+
+#
+# Create shell aliases
+#
+# Create Python based aliases for common shell commands like copy or move.
+#
+COPY = python $(PEPPER_ROOT)/tools/oshelpers.py cp
+MKDIR = python $(PEPPER_ROOT)/tools/oshelpers.py mkdir
+RM = python $(PEPPER_ROOT)/tools/oshelpers.py rm
+MV = python $(PEPPER_ROOT)/tools/oshelpers.py mv
+
+#
+# Disable DOS PATH warning when using Cygwin based tools Windows
+#
+CYGWIN ?= nodosfilewarning
+export CYGWIN
+
+#
+# Define a macro for copying files to the configuration directory
+#
+# Copys a source file to the destination directory, removing the base path
+# from the source. Adds a dependency to the destination directory in case it
+# needs to be created.
+#
+# $(1) = Source file
+# $(2) = Destination directory
+define FILE_COPY
+$(2)/$(notdir $(1)) : $(1) | $(2)
+ $(COPY) $(1) $(2)
+$(2)_COPIES+=$(2)/$(notdir $(1))
+endef
+
+
+# Declare the ALL target first, to make the 'all' target the default build
+all: DEBUG RELEASE
+
+
+#
+# Debug Build rules.
+#
+DEBUG_x86_32_FLAGS:=-m32 -O0 -g
+DEBUG_x86_64_FLAGS:=-m64 -O0 -g
+DEBUG_x86_32_OBJS:=$(patsubst %.cc,DBG/x86_32/%.o,$(CXX_SOURCES))
+DEBUG_x86_64_OBJS:=$(patsubst %.cc,DBG/x86_64/%.o,$(CXX_SOURCES))
+
+# Create DBG configuration directories
+DBG:
+ $(MKDIR) -p $@
+
+DBG/x86_32:
+ $(MKDIR) -p $@
+
+DBG/x86_64:
+ $(MKDIR) -p $@
+
+# Copy all files to that config
+$(foreach src,$(COPY_FILES),$(eval $(call FILE_COPY,$(src),DBG)))
+
+# Include generated dependencies
+-include DBG/x86_32/*.d
+-include DBG/x86_64/*.d
+
+# Define compile rule for all 32 bit debug objects
+DBG/x86_32/%.o : %.cc $(THIS_MAKE) | DBG/x86_32
+ $(CXX) -o $@ -c $< $(DEBUG_x86_32_FLAGS) $(CXXFLAGS) -MMD -MF $@.d
+
+# Define compile rule for all 64 bit debug objects
+DBG/x86_64/%.o : %.cc $(THIS_MAKE) | DBG/x86_64
+ $(CXX) -o $@ -c $< $(DEBUG_x86_64_FLAGS) $(CXXFLAGS)
+
+# Define Link rule for 32 bit debug NEXE
+DBG/$(PROJECT)_x86_32.nexe : $(DEBUG_x86_32_OBJS)
+ $(CXX) -o $@ $^ $(DEBUG_x86_32_FLAGS) $(LDFLAGS)
+
+# Define Link rule for 64 bit debug NEXE
+DBG/$(PROJECT)_x86_64.nexe : $(DEBUG_x86_64_OBJS)
+ $(CXX) -o $@ $^ $(DEBUG_x86_64_FLAGS) $(LDFLAGS)
+
+# Define a DEBUG alias to build the debug version
+.PHONY : DEBUG RUN_DEBUG
+DEBUG : DBG/$(PROJECT)_x86_32.nexe DBG/$(PROJECT)_x86_64.nexe $(DBG_COPIES)
+
+# Define a RUN_DEBUG alias to build and server the DEBUG version
+RUN_DEBUG: DEBUG
+ cd DBG && python ../../httpd.py
+
+
+#
+# Release build rules.
+#
+RELEASE_x86_32_FLAGS:=-m32 -O2 -g
+RELEASE_x86_64_FLAGS:=-m64 -O2 -g
+RELEASE_x86_32_OBJS:=$(patsubst %.cc,REL/x86_32/%.o,$(CXX_SOURCES))
+RELEASE_x86_64_OBJS:=$(patsubst %.cc,REL/x86_64/%.o,$(CXX_SOURCES))
+
+REL:
+ $(MKDIR) -p $@
+
+REL/x86_32:
+ $(MKDIR) -p $@
+
+REL/x86_64:
+ $(MKDIR) -p $@
+
+# Copy all files to that config
+$(foreach src,$(COPY_FILES),$(eval $(call FILE_COPY,$(src),REL)))
+
+# Include generated dependencies
+-include REL/x86_32/*.d
+-include REL/x86_64/*.d
+
+# Define compile rule for all 32 bit debug objects
+REL/x86_32/%.o : %.cc $(THIS_MAKE) | REL/x86_32
+ $(CXX) -o $@ -c $< $(RELEASE_x86_32_FLAGS) $(CXXFLAGS) -MMD -MF $@.d
+
+# Define compile rule for all 64 bit debug objects
+REL/x86_64/%.o : %.cc $(THIS_MAKE) | REL/x86_64
+ $(CXX) -o $@ -c $< $(RELEASE_x86_64_FLAGS) $(CXXFLAGS)
+
+# Define Link rule for 32 bit optimized and stripped NEXE
+REL/$(PROJECT)_x86_32.nexe : $(RELEASE_x86_32_OBJS)
+ $(CXX) -o $@.unstripped $^ $(RELEASE_x86_32_FLAGS) $(LDFLAGS)
+ $(STRIP) $< -o $@
+
+# Define Link rule for 64 bit optimized and stripped NEXE
+REL/$(PROJECT)_x86_64.nexe : $(RELEASE_x86_64_OBJS)
+ $(CXX) -o $@.unstripped $^ $(RELEASE_x86_64_FLAGS) $(LDFLAGS)
+ $(STRIP) $@.unstripped -o $@
+
+# Define a RELEASE alias to build the debug version
+.PHONY : RELEASE RUN_RELEASE
+RELEASE : REL/$(PROJECT)_x86_32.nexe REL/$(PROJECT)_x86_64.nexe $(REL_COPIES)
+
+# Define a RUN_RELEASE alias to build and server the RELEASE version
+RUN_RELEASE: RELEASE
+ cd REL && python ../../httpd.py
diff --git a/native_client_sdk/src/examples/gamepad/gamepad.cc b/native_client_sdk/src/examples/gamepad/gamepad.cc
new file mode 100644
index 0000000..c288b8b
--- /dev/null
+++ b/native_client_sdk/src/examples/gamepad/gamepad.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2012 The Native Client Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gamepad.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <cassert>
+#include <cmath>
+#include <cstring>
+#include <string>
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/var.h"
+
+namespace {
+
+// This is called by the browser when the 2D context has been flushed to the
+// browser window.
+void FlushCallback(void* data, int32_t result) {
+ static_cast<gamepad::Gamepad*>(data)->set_flush_pending(false);
+ static_cast<gamepad::Gamepad*>(data)->Paint();
+}
+
+} // namespace
+
+namespace gamepad {
+
+Gamepad::Gamepad(PP_Instance instance)
+ : pp::Instance(instance),
+ graphics_2d_context_(NULL),
+ pixel_buffer_(NULL),
+ flush_pending_(false),
+ quit_(false) {
+ pp::Module* module = pp::Module::Get();
+ assert(module);
+ gamepad_ = static_cast<const PPB_Gamepad_Dev*>(
+ module->GetBrowserInterface(PPB_GAMEPAD_DEV_INTERFACE));
+ assert(gamepad_);
+}
+
+Gamepad::~Gamepad() {
+ quit_ = true;
+ DestroyContext();
+ delete pixel_buffer_;
+}
+
+void Gamepad::DidChangeView(const pp::Rect& position,
+ const pp::Rect& clip) {
+ if (position.size().width() == width() &&
+ position.size().height() == height())
+ return; // Size didn't change, no need to update anything.
+
+ // Create a new device context with the new size.
+ DestroyContext();
+ CreateContext(position.size());
+ // Delete the old pixel buffer and create a new one.
+ delete pixel_buffer_;
+ pixel_buffer_ = NULL;
+ if (graphics_2d_context_ != NULL) {
+ pixel_buffer_ = new pp::ImageData(this,
+ PP_IMAGEDATAFORMAT_BGRA_PREMUL,
+ graphics_2d_context_->size(),
+ false);
+ }
+ Paint();
+}
+
+void FillRect(pp::ImageData* image, int left, int top, int width, int height,
+ uint32_t color) {
+ for (int y = std::max(0, top);
+ y < std::min(image->size().height() - 1, top + height);
+ y++) {
+ for (int x = std::max(0, left);
+ x < std::min(image->size().width() - 1, left + width);
+ x++)
+ *image->GetAddr32(pp::Point(x, y)) = color;
+ }
+}
+
+void Gamepad::Paint() {
+ // Clear the background.
+ FillRect(pixel_buffer_, 0, 0, width(), height(), 0xfff0f0f0);
+
+ // Get current gamepad data.
+ PP_GamepadsData_Dev gamepad_data;
+ gamepad_->SampleGamepads(pp_instance(), &gamepad_data);
+
+ // Draw the current state for each connected gamepad.
+ for (size_t p = 0; p < gamepad_data.length; ++p) {
+ int width2 = width() / gamepad_data.length / 2;
+ int height2 = height() / 2;
+ int offset = width2 * 2 * p;
+ PP_GamepadData_Dev& pad = gamepad_data.items[p];
+
+ if (!pad.connected)
+ continue;
+
+ // Draw axes.
+ for (size_t i = 0; i < pad.axes_length; i += 2) {
+ int x = static_cast<int>(pad.axes[i + 0] * width2 + width2) + offset;
+ int y = static_cast<int>(pad.axes[i + 1] * height2 + height2);
+ uint32_t box_bgra = 0x80000000; // Alpha 50%.
+ FillRect(pixel_buffer_, x - 3, y - 3, 7, 7, box_bgra);
+ }
+
+ // Draw buttons.
+ for (size_t i = 0; i < pad.buttons_length; ++i) {
+ float button_val = pad.buttons[i];
+ uint32_t colour = static_cast<uint32_t>((button_val * 192) + 63) << 24;
+ int x = i * 8 + 10 + offset;
+ int y = 10;
+ FillRect(pixel_buffer_, x - 3, y - 3, 7, 7, colour);
+ }
+ }
+
+ // Output to the screen.
+ FlushPixelBuffer();
+}
+
+void Gamepad::CreateContext(const pp::Size& size) {
+ if (IsContextValid())
+ return;
+ graphics_2d_context_ = new pp::Graphics2D(this, size, false);
+ if (!BindGraphics(*graphics_2d_context_)) {
+ printf("Couldn't bind the device context\n");
+ }
+}
+
+void Gamepad::DestroyContext() {
+ if (!IsContextValid())
+ return;
+ delete graphics_2d_context_;
+ graphics_2d_context_ = NULL;
+}
+
+void Gamepad::FlushPixelBuffer() {
+ if (!IsContextValid())
+ return;
+ // Note that the pixel lock is held while the buffer is copied into the
+ // device context and then flushed.
+ graphics_2d_context_->PaintImageData(*pixel_buffer_, pp::Point());
+ if (flush_pending())
+ return;
+ set_flush_pending(true);
+ graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
+}
+
+} // namespace gamepad
diff --git a/native_client_sdk/src/examples/gamepad/gamepad.h b/native_client_sdk/src/examples/gamepad/gamepad.h
new file mode 100644
index 0000000..e5a5e3a
--- /dev/null
+++ b/native_client_sdk/src/examples/gamepad/gamepad.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Native Client Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXAMPLES_GAMEPAD_GAMEPAD_H_
+#define EXAMPLES_GAMEPAD_GAMEPAD_H_
+
+#include <map>
+#include <vector>
+#include "ppapi/c/dev/ppb_gamepad_dev.h"
+#include "ppapi/cpp/graphics_2d.h"
+#include "ppapi/cpp/image_data.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/size.h"
+
+namespace gamepad {
+
+// The Instance class. One of these exists for each instance of your NaCl
+// module on the web page. The browser will ask the Module object to create
+// a new Instance for each occurrence of the <embed> tag that has these
+// attributes:
+// type="application/x-nacl"
+// nacl="pi_generator.nmf"
+class Gamepad : public pp::Instance {
+ public:
+ explicit Gamepad(PP_Instance instance);
+ virtual ~Gamepad();
+
+ // Update the graphics context to the new size, and regenerate |pixel_buffer_|
+ // to fit the new size as well.
+ virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip);
+
+ // Flushes its contents of |pixel_buffer_| to the 2D graphics context.
+ void Paint();
+
+ bool quit() const {
+ return quit_;
+ }
+
+ int width() const {
+ return pixel_buffer_ ? pixel_buffer_->size().width() : 0;
+ }
+ int height() const {
+ return pixel_buffer_ ? pixel_buffer_->size().height() : 0;
+ }
+
+ // Indicate whether a flush is pending. This can only be called from the
+ // main thread; it is not thread safe.
+ bool flush_pending() const {
+ return flush_pending_;
+ }
+ void set_flush_pending(bool flag) {
+ flush_pending_ = flag;
+ }
+
+ private:
+ // Create and initialize the 2D context used for drawing.
+ void CreateContext(const pp::Size& size);
+ // Destroy the 2D drawing context.
+ void DestroyContext();
+ // Push the pixels to the browser, then attempt to flush the 2D context. If
+ // there is a pending flush on the 2D context, then update the pixels only
+ // and do not flush.
+ void FlushPixelBuffer();
+
+ bool IsContextValid() const {
+ return graphics_2d_context_ != NULL;
+ }
+
+ pp::Graphics2D* graphics_2d_context_;
+ pp::ImageData* pixel_buffer_;
+ const PPB_Gamepad_Dev* gamepad_;
+ bool flush_pending_;
+ bool quit_;
+};
+
+} // namespace gamepad
+
+#endif // EXAMPLES_GAMEPAD_GAMEPAD_H_
diff --git a/native_client_sdk/src/examples/gamepad/gamepad.html b/native_client_sdk/src/examples/gamepad/gamepad.html
new file mode 100644
index 0000000..65c0fff
--- /dev/null
+++ b/native_client_sdk/src/examples/gamepad/gamepad.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <!--
+ Copyright (c) 2012 The Native Client Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+ -->
+ <head>
+ <title>Gamepad example</title>
+ </head>
+ <body id="bodyId">
+
+ <p> Attached gamepad values should appear, left to right, once they've been
+ interacted with. Buttons, esp triggers are analog (alpha). </p>
+
+ <embed
+ name="nacl_module"
+ id="gamepad"
+ width=800 height=200
+ src="gamepad.nmf"
+ type="application/x-nacl" />
+ </body>
+</html>
diff --git a/native_client_sdk/src/examples/gamepad/gamepad.nmf b/native_client_sdk/src/examples/gamepad/gamepad.nmf
new file mode 100644
index 0000000..53e3b97
--- /dev/null
+++ b/native_client_sdk/src/examples/gamepad/gamepad.nmf
@@ -0,0 +1,6 @@
+{
+ "program": {
+ "x86-64": {"url": "gamepad_x86_64.nexe"},
+ "x86-32": {"url": "gamepad_x86_32.nexe"}
+ }
+}
diff --git a/native_client_sdk/src/examples/gamepad/gamepad_module.cc b/native_client_sdk/src/examples/gamepad/gamepad_module.cc
new file mode 100644
index 0000000..cac2570
--- /dev/null
+++ b/native_client_sdk/src/examples/gamepad/gamepad_module.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Native Client Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ppapi/cpp/module.h>
+
+#include "gamepad.h"
+
+namespace gamepad {
+// The Module class. The browser calls the CreateInstance() method to create
+// an instance of your NaCl module on the web page. The browser creates a new
+// instance for each <embed> tag with type="application/x-nacl".
+class GamepadModule : public pp::Module {
+ public:
+ GamepadModule() : pp::Module() {}
+ virtual ~GamepadModule() {}
+
+ // Create and return a GamepadInstance object.
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new Gamepad(instance);
+ }
+};
+} // namespace gamepad
+
+// Factory function called by the browser when the module is first loaded.
+// The browser keeps a singleton of this module. It calls the
+// CreateInstance() method on the object you return to make instances. There
+// is one instance per <embed> tag on the page. This is the main binding
+// point for your NaCl module with the browser.
+namespace pp {
+Module* CreateModule() {
+ return new gamepad::GamepadModule();
+}
+} // namespace pp