diff options
author | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-30 20:31:40 +0000 |
---|---|---|
committer | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-30 20:31:40 +0000 |
commit | b31d645164494c33d74a1a8493ea37e5de9cd21f (patch) | |
tree | 2355317c38d5cf7600585911197b0da7195fb1c7 | |
parent | c731ac75dd33b52655f0b64a7e8366ebc86b87d0 (diff) | |
download | chromium_src-b31d645164494c33d74a1a8493ea37e5de9cd21f.zip chromium_src-b31d645164494c33d74a1a8493ea37e5de9cd21f.tar.gz chromium_src-b31d645164494c33d74a1a8493ea37e5de9cd21f.tar.bz2 |
Add 3D version of instance.
Add an example which uses the ppapi_main and nacl_mounts to simplify the 3D example.
NOTRY=true
R=binji@chromium.org
BUG=168867
Review URL: https://codereview.chromium.org/11647030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@179692 0039d316-1c4b-4281-b951-d872f2087c98
26 files changed, 1376 insertions, 54 deletions
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py index 320e468..38a5e4b 100755 --- a/native_client_sdk/src/build_tools/build_sdk.py +++ b/native_client_sdk/src/build_tools/build_sdk.py @@ -607,6 +607,7 @@ EXAMPLE_LIST = [ 'hello_world_stdio', 'hello_world', 'hello_world_gles', + 'hello_world_instance3d', 'hello_world_interactive', 'input_events', 'load_progress', diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/Makefile b/native_client_sdk/src/examples/hello_nacl_mounts/Makefile index 8a24b63..c4d9da8 100644 --- a/native_client_sdk/src/examples/hello_nacl_mounts/Makefile +++ b/native_client_sdk/src/examples/hello_nacl_mounts/Makefile @@ -16,7 +16,7 @@ # to override this, specify TOOLCHAIN=newlib|glibc or CONFIG=Debug|Release on # the make command-line or in this file prior to including common.mk. The # toolchain we use by default will be the first valid one listed -VALID_TOOLCHAINS:=newlib glibc win +VALID_TOOLCHAINS:=newlib glibc pnacl win # diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc b/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc index ea55c44..0ac6dd6 100644 --- a/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc +++ b/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc @@ -1,5 +1,5 @@ { - 'TOOLS': ['newlib', 'glibc', 'win'], + 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'], 'TARGETS': [ { 'NAME' : 'hello_nacl_mounts', diff --git a/native_client_sdk/src/examples/hello_world_instance3d/Makefile b/native_client_sdk/src/examples/hello_world_instance3d/Makefile new file mode 100644 index 0000000..41d3833 --- /dev/null +++ b/native_client_sdk/src/examples/hello_world_instance3d/Makefile @@ -0,0 +1,81 @@ +# Copyright (c) 2012 The Chromium 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 +# +# + + +# +# Default configuration +# +# By default we will build a Debug configuration using the GCC newlib toolcahin +# to override this, specify TOOLCHAIN=newlib|glibc or CONFIG=Debug|Release on +# the make command-line or in this file prior to including common.mk. The +# toolchain we use by default will be the first valid one listed +VALID_TOOLCHAINS:=newlib glibc pnacl + + +# +# Get pepper directory for toolchain and includes. +# +# If NACL_SDK_ROOT is not set, then assume it can be found relative to +# to this Makefile. +# +NACL_SDK_ROOT?=$(abspath $(CURDIR)/../..) +include $(NACL_SDK_ROOT)/tools/common.mk + + +# +# Target Name +# +# The base name of the final NEXE, also the name of the NMF file containing +# the mapping between architecture and actual NEXE. +# +TARGET=hello_world_instance3d + +# +# List of sources to compile +# +SOURCES=hello_world.cc matrix.cc + + +# +# List of libraries to link against. Unlike some tools, the GCC and LLVM +# based tools require libraries to be specified in the correct order. The +# order should be symbol reference followed by symbol definition, with direct +# sources to the link (object files) are left most. In this case: +# hello_world -> ppapi_main -> ppapi_cpp -> ppapi -> pthread -> libc +# Notice that libc is implied and come last through standard compiler/link +# switches. +# +# We break this list down into two parts, the set we need to rebuild (DEPS) +# and the set we do not. This example does not have any additional library +# dependencies. +# +DEPS=ppapi_main nacl_mounts ppapi_cpp ppapi_gles2 +LIBS=$(DEPS) ppapi pthread + + +# +# Use the library dependency macro for each dependency +# +$(foreach dep,$(DEPS),$(eval $(call DEPEND_RULE,$(dep)))) + +# +# Use the compile macro for each source. +# +$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src)))) + +# +# Use the link macro for this target on the list of sources. +# +$(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS))) + +# +# Specify the NMF to be created with no additional arugments. +# +$(eval $(call NMF_RULE,$(TARGET),)) diff --git a/native_client_sdk/src/examples/hello_world_instance3d/example.dsc b/native_client_sdk/src/examples/hello_world_instance3d/example.dsc new file mode 100644 index 0000000..128f40c --- /dev/null +++ b/native_client_sdk/src/examples/hello_world_instance3d/example.dsc @@ -0,0 +1,34 @@ +{ + 'TOOLS': ['newlib', 'glibc', 'pnacl'], + 'TARGETS': [ + { + 'NAME' : 'hello_world_instance3d', + 'TYPE' : 'main', + 'SOURCES' : ['hello_world.cc', 'matrix.cc', 'matrix.h'], + 'CXXFLAGS': [ + '-I../../src', + '-I../../src/ppapi/lib/gl' + ], + 'LIBS': ['ppapi_main', 'nacl_mounts', 'ppapi_gles2', 'ppapi_cpp', 'ppapi', + 'pthread'] + } + ], + 'DATA': [ + 'Makefile', + 'fragment_shader_es2.frag', + 'hello.raw', + 'vertex_shader_es2.vert' + ], + 'DEST': 'examples', + 'NAME': 'hello_world_instance3d', + 'TITLE': 'Hello World GLES 2.0 using ppapi_instance3d', + 'DESC': """ +The Hello World GLES 2.0 example demonstrates how to create a 3D cube +that rotates. This is a simpler example than the tumbler example, and +written in C. It loads the assets using URLLoader.""", + 'FOCUS': '3D graphics, URL Loader.', + 'GROUP': 'API' +} + + + diff --git a/native_client_sdk/src/examples/hello_world_instance3d/fragment_shader_es2.frag b/native_client_sdk/src/examples/hello_world_instance3d/fragment_shader_es2.frag new file mode 100644 index 0000000..247c559 --- /dev/null +++ b/native_client_sdk/src/examples/hello_world_instance3d/fragment_shader_es2.frag @@ -0,0 +1,8 @@ +precision mediump float; +varying vec3 v_color; +varying vec2 v_texCoord; +uniform sampler2D s_texture; +void main() +{ + gl_FragColor = texture2D( s_texture, vec2(v_texCoord.x,1.0 - v_texCoord.y) ) + vec4(v_color.x,v_color.y,v_color.z,1); +}
\ No newline at end of file diff --git a/native_client_sdk/src/examples/hello_world_instance3d/hello_world.cc b/native_client_sdk/src/examples/hello_world_instance3d/hello_world.cc new file mode 100644 index 0000000..304c0fb --- /dev/null +++ b/native_client_sdk/src/examples/hello_world_instance3d/hello_world.cc @@ -0,0 +1,313 @@ +/* Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** @file hello_world_gles.cc + * This example demonstrates loading and running a simple 3D openGL ES 2.0 + * application. + */ + +//--------------------------------------------------------------------------- +// The spinning Cube +//--------------------------------------------------------------------------- + +#define _USE_MATH_DEFINES 1 +#include <fcntl.h> +#include <limits.h> +#include <math.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "nacl_mounts/nacl_mounts.h" + +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb.h" +#include "ppapi/c/ppb_opengles2.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/c/ppp.h" +#include "ppapi/c/ppp_graphics_3d.h" +#include "ppapi/c/ppp_instance.h" + +#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h" + +#include "ppapi_main/ppapi_event.h" +#include "ppapi_main/ppapi_instance3d.h" +#include "ppapi_main/ppapi_main.h" + +#include <GLES2/gl2.h> +#include "matrix.h" + +GLuint g_positionLoc; +GLuint g_texCoordLoc; +GLuint g_colorLoc; +GLuint g_MVPLoc; +GLuint g_vboID; +GLuint g_ibID; +GLubyte g_Indices[36]; + +GLuint g_programObj; +GLuint g_vertexShader; +GLuint g_fragmentShader; + +GLuint g_textureLoc = 0; +GLuint g_textureID = 0; + +float g_fSpinX = 0.0f; +float g_fSpinY = 0.0f; + +//---------------------------------------------------------------------------- +// Rendering Assets +//---------------------------------------------------------------------------- +struct Vertex +{ + float tu, tv; + float color[3]; + float loc[3]; +}; + +Vertex *g_quadVertices = NULL; +const char *g_TextureData = NULL; +const char *g_VShaderData = NULL; +const char *g_FShaderData = NULL; + +bool g_Loaded = false; +bool g_Ready = false; + + +float g_xSpin = 2.0f; +float g_ySpin = 0.5f; + + +GLuint compileShader(GLenum type, const char *data) { + const char *shaderStrings[1]; + shaderStrings[0] = data; + + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, shaderStrings, NULL ); + glCompileShader(shader); + return shader; +} + + +void InitProgram(void) { + g_vertexShader = compileShader(GL_VERTEX_SHADER, g_VShaderData); + g_fragmentShader = compileShader(GL_FRAGMENT_SHADER, g_FShaderData); + + g_programObj = glCreateProgram(); + glAttachShader(g_programObj, g_vertexShader); + glAttachShader(g_programObj, g_fragmentShader); + glLinkProgram(g_programObj); + + glGenBuffers(1, &g_vboID); + glBindBuffer(GL_ARRAY_BUFFER, g_vboID); + glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(Vertex), + (void*)&g_quadVertices[0], GL_STATIC_DRAW); + + glGenBuffers(1, &g_ibID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ibID); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36 * sizeof(char), + (void*)&g_Indices[0], GL_STATIC_DRAW); + + // + // Create a texture to test out our fragment shader... + // + glGenTextures(1, &g_textureID); + glBindTexture(GL_TEXTURE_2D, g_textureID); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, + GL_UNSIGNED_BYTE, g_TextureData); + + // + // Locate some parameters by name so we can set them later... + // + g_textureLoc = glGetUniformLocation(g_programObj, "arrowTexture"); + g_positionLoc = glGetAttribLocation(g_programObj, "a_position"); + g_texCoordLoc = glGetAttribLocation(g_programObj, "a_texCoord"); + g_colorLoc = glGetAttribLocation(g_programObj, "a_color"); + g_MVPLoc = glGetUniformLocation(g_programObj, "a_MVP"); + printf("Program initialized.\n"); +} + + +void BuildQuad(Vertex* verts, int axis[3], float depth, float color[3]) { + static float X[4] = { -1.0f, 1.0f, 1.0f, -1.0f }; + static float Y[4] = { -1.0f, -1.0f, 1.0f, 1.0f }; + + for (int i = 0; i < 4; i++) { + verts[i].tu = (1.0 - X[i]) / 2.0f; + verts[i].tv = (Y[i] + 1.0f) / -2.0f * depth; + verts[i].loc[axis[0]] = X[i] * depth; + verts[i].loc[axis[1]] = Y[i] * depth; + verts[i].loc[axis[2]] = depth; + for (int j = 0; j < 3; j++) + verts[i].color[j] = color[j] * (Y[i] + 1.0f) / 2.0f; + } +} + + +Vertex *BuildCube() { + Vertex *verts = new Vertex[24]; + for (int i = 0; i < 3; i++) { + int Faxis[3]; + int Baxis[3]; + float Fcolor[3]; + float Bcolor[3]; + for (int j = 0; j < 3; j++) { + Faxis[j] = (j + i) % 3; + Baxis[j] = (j + i) % 3; + } + memset(Fcolor, 0, sizeof(float) * 3); + memset(Bcolor, 0, sizeof(float) * 3); + Fcolor[i] = 0.5f; + Bcolor[i] = 1.0f; + BuildQuad(&verts[0 + i * 4], Faxis, 1.0f, Fcolor); + BuildQuad(&verts[12 + i * 4], Baxis, -1.0f, Bcolor); + } + + for(int i = 0; i < 6; i++) { + g_Indices[i*6 + 0] = 2 + i * 4; + g_Indices[i*6 + 1] = 1 + i * 4; + g_Indices[i*6 + 2] = 0 + i * 4; + g_Indices[i*6 + 3] = 3 + i * 4; + g_Indices[i*6 + 4] = 2 + i * 4; + g_Indices[i*6 + 5] = 0 + i * 4; + } + return verts; +} + + +static float clamp(float val, float min, float max) { + if (val < min) return min; + if (val > max) return max; + return val; +} + + +void ProcessEvent(PPAPIEvent* event) { + if (event->event_type == PP_INPUTEVENT_TYPE_MOUSEMOVE) { + PPAPIMouseEvent* mouse = (PPAPIMouseEvent*) event; + g_ySpin = clamp((float) mouse->delta.x / 2, -4.0, 4.0); + g_xSpin = clamp((float) mouse->delta.y / 2, -4.0, 4.0); + } + if (event->event_type == PP_INPUTEVENT_TYPE_KEYUP) { + PPAPIKeyEvent* key = (PPAPIKeyEvent*) event; + if (key->key_code == 13) { + PPAPIInstance3D::GetInstance3D()->ToggleFullscreen(); + } + } +} + +void PPAPIRender(uint32_t width, uint32_t height) { + if (!g_Ready) { + if (g_Loaded) { + InitProgram(); + g_Ready = true; + } else { + return; + } + } + + PPAPIEvent* event; + while (PPAPIEvent* event = PPAPI_AcquireEvent()) { + ProcessEvent(event); + PPAPI_ReleaseEvent(event); + } + + static float xRot = 0.0; + static float yRot = 0.0; + + xRot -= g_xSpin; + yRot -= g_ySpin; + + if (xRot >= 360.0f) xRot = 0.0; + if (xRot <= -360.0f) xRot = 0.0; + + if (yRot >= 360.0f) yRot = 0.0; + if (yRot <= -360.0f) yRot = 0.0; + + glClearColor(0.5,0.5,0.5,1); + glClearDepthf(1.0); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glEnable(GL_DEPTH_TEST); + + //set what program to use + glUseProgram( g_programObj ); + glActiveTexture ( GL_TEXTURE0 ); + glBindTexture ( GL_TEXTURE_2D,g_textureID ); + glUniform1i ( g_textureLoc, 0 ); + + //create our perspective matrix + float mpv[16]; + float trs[16]; + float rot[16]; + + identity_matrix(mpv); + glhPerspectivef2(&mpv[0], 45.0f, (float) (width) / (float) height, 1, 10); + + translate_matrix(0, 0, -4.0, trs); + rotate_matrix(xRot, yRot , 0.0f ,rot); + multiply_matrix(trs, rot, trs); + multiply_matrix(mpv, trs, mpv); + glUniformMatrix4fv(g_MVPLoc, 1, GL_FALSE, (GLfloat*) mpv); + + //define the attributes of the vertex + glBindBuffer(GL_ARRAY_BUFFER, g_vboID); + glVertexAttribPointer(g_positionLoc, 3, GL_FLOAT, GL_FALSE, + sizeof(Vertex), (void*)offsetof(Vertex,loc)); + glEnableVertexAttribArray(g_positionLoc); + glVertexAttribPointer(g_texCoordLoc, 2, GL_FLOAT, GL_FALSE, + sizeof(Vertex), (void*)offsetof(Vertex,tu)); + glEnableVertexAttribArray(g_texCoordLoc); + glVertexAttribPointer(g_colorLoc, 3, GL_FLOAT, GL_FALSE, + sizeof(Vertex), (void*)offsetof(Vertex,color)); + glEnableVertexAttribArray(g_colorLoc); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ibID); + glDrawElements ( GL_TRIANGLES, 36, GL_UNSIGNED_BYTE ,0 ); +} + + +const char *LoadData(const char *url) { + char *buf; + struct stat stat_buf; + + int fp = open(url, O_RDONLY); + fstat(fp, &stat_buf); + + int len = static_cast<int>(stat_buf.st_size); + buf = new char[len + 1]; + int read_size = read(fp, buf, len); + buf[len] = 0; + return buf; +} + + +PPAPI_MAIN_USE(PPAPI_CreateInstance3D, PPAPI_MAIN_DEFAULT_ARGS) +int ppapi_main(int argc, const char *argv[]) { + printf("Started main.\n"); + + // Mount URL loads to /http + mount("", "/http", "httpfs", 0, ""); + + g_TextureData = LoadData("/http/hello.raw"); + g_VShaderData = LoadData("/http/vertex_shader_es2.vert"); + g_FShaderData = LoadData("/http/fragment_shader_es2.frag"); + g_quadVertices = BuildCube(); + + fprintf(stderr,"Loaded\n"); + g_Loaded = true; + return 0; +} diff --git a/native_client_sdk/src/examples/hello_world_instance3d/index.html b/native_client_sdk/src/examples/hello_world_instance3d/index.html new file mode 100644 index 0000000..cfc9ddd --- /dev/null +++ b/native_client_sdk/src/examples/hello_world_instance3d/index.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright (c) 2012 The Chromium 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> + <meta http-equiv="Pragma" content="no-cache"> + <meta http-equiv="Expires" content="-1"> + <title><TITLE></title> + <script type="text/javascript" src="common.js"></script> +</head> +<body data-name="<NAME>" data-tc="<tc>" data-path="<path>" data-width="640" + data-height="480"> + <h1><TITLE></h1> + <h2>Status: <code id="statusField">NO-STATUS</code></h2> + <!-- The NaCl plugin will be embedded inside the element with id "listener". + See common.js.--> + <div id="listener"></div> +</body> +</html> diff --git a/native_client_sdk/src/examples/hello_world_instance3d/matrix.cc b/native_client_sdk/src/examples/hello_world_instance3d/matrix.cc new file mode 100644 index 0000000..32200c7 --- /dev/null +++ b/native_client_sdk/src/examples/hello_world_instance3d/matrix.cc @@ -0,0 +1,136 @@ +/* Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** @file matrix.cc + * Implements simple matrix manipulation functions. + */ + +//----------------------------------------------------------------------------- +#include <stdlib.h> +#include <string.h> +#include "matrix.h" +#define deg_to_rad(x) (x * (M_PI/180.0f)) + +void glhFrustumf2(Matrix_t mat, GLfloat left, GLfloat right, GLfloat bottom, + GLfloat top, GLfloat znear, GLfloat zfar) +{ + float temp, temp2, temp3, temp4; + temp = 2.0f * znear; + temp2 = right - left; + temp3 = top - bottom; + temp4 = zfar - znear; + mat[0] = temp / temp2; + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; + mat[4] = 0.0f; + mat[5] = temp / temp3; + mat[6] = 0.0f; + mat[7] = 0.0f; + mat[8] = (right + left) / temp2; + mat[9] = (top + bottom) / temp3; + mat[10] = (-zfar - znear) / temp4; + mat[11] = -1.0f; + mat[12] = 0.0f; + mat[13] = 0.0f; + mat[14] = (-temp * zfar) / temp4; + mat[15] = 0.0f; +} + +void glhPerspectivef2(Matrix_t mat, GLfloat fovyInDegrees, + GLfloat aspectRatio, GLfloat znear, GLfloat zfar) +{ + float ymax, xmax; + ymax = znear * tanf(fovyInDegrees * 3.14f / 360.0f); + xmax = ymax * aspectRatio; + glhFrustumf2(mat, -xmax, xmax, -ymax, ymax, znear, zfar); +} + +void identity_matrix(Matrix_t mat) { + memset(mat, 0, sizeof(Matrix_t)); + mat[0] = 1.0; + mat[5] = 1.0; + mat[10] = 1.0; + mat[15] = 1.0; +} + +void multiply_matrix(const Matrix_t a, const Matrix_t b, Matrix_t mat) { + // Generate to a temporary first in case the output matrix and input + // matrix are thes same. + Matrix_t out; + + out[0] = a[0] * b[0] + a[4] * b[1] + a[8] * b[2] + a[12] * b[3]; + out[1] = a[1] * b[0] + a[5] * b[1] + a[9] * b[2] + a[13] * b[3]; + out[2] = a[2] * b[0] + a[6] * b[1] + a[10] * b[2] + a[14] * b[3]; + out[3] = a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + a[15] * b[3]; + + out[4] = a[0] * b[4] + a[4] * b[5] + a[8] * b[6] + a[12] * b[7]; + out[5] = a[1] * b[4] + a[5] * b[5] + a[9] * b[6] + a[13] * b[7]; + out[6] = a[2] * b[4] + a[6] * b[5] + a[10] * b[6] + a[14] * b[7]; + out[7] = a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + a[15] * b[7]; + + out[8] = a[0] * b[8] + a[4] * b[9] + a[8] * b[10] + a[12] * b[11]; + out[9] = a[1] * b[8] + a[5] * b[9] + a[9] * b[10] + a[13] * b[11]; + out[10] = a[2] * b[8] + a[6] * b[9] + a[10] * b[10] + a[14] * b[11]; + out[11] = a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + a[15] * b[11]; + + out[12] = a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12] * b[15]; + out[13] = a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13] * b[15]; + out[14] = a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15]; + out[15] = a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15]; + + memcpy(mat, out, sizeof(Matrix_t)); +} + +void rotate_x_matrix(GLfloat x_rad, Matrix_t mat) { + identity_matrix(mat); + mat[5] = cosf(x_rad); + mat[6] = -sinf(x_rad); + mat[9] = -mat[6]; + mat[10] = mat[5]; +} + +void rotate_y_matrix(GLfloat y_rad, Matrix_t mat) { + identity_matrix(mat); + mat[0] = cosf(y_rad); + mat[2] = sinf(y_rad); + mat[8] = -mat[2]; + mat[10] = mat[0]; +} + +void rotate_z_matrix(GLfloat z_rad, Matrix_t mat) { + identity_matrix(mat); + mat[0] = cosf(z_rad); + mat[1] = sinf(z_rad); + mat[4] = -mat[1]; + mat[5] = mat[0]; +} + +void rotate_matrix(GLfloat x_deg, GLfloat y_deg, GLfloat z_deg, + Matrix_t mat) { + GLfloat x_rad = (GLfloat) deg_to_rad(x_deg); + GLfloat y_rad = (GLfloat) deg_to_rad(y_deg); + GLfloat z_rad = (GLfloat) deg_to_rad(z_deg); + + Matrix_t x_matrix; + Matrix_t y_matrix; + Matrix_t z_matrix; + + rotate_x_matrix(x_rad, x_matrix); + rotate_y_matrix(y_rad, y_matrix); + rotate_z_matrix(z_rad, z_matrix); + + Matrix_t xy_matrix; + multiply_matrix(y_matrix, x_matrix, xy_matrix); + multiply_matrix(z_matrix, xy_matrix, mat); +} + +void translate_matrix(GLfloat x, GLfloat y, GLfloat z, Matrix_t mat) { + identity_matrix(mat); + mat[12] += x; + mat[13] += y; + mat[14] += z; +} + diff --git a/native_client_sdk/src/examples/hello_world_instance3d/matrix.h b/native_client_sdk/src/examples/hello_world_instance3d/matrix.h new file mode 100644 index 0000000..7db7985 --- /dev/null +++ b/native_client_sdk/src/examples/hello_world_instance3d/matrix.h @@ -0,0 +1,37 @@ +#ifndef EXAMPLES_HELLO_WORLD_GLES_MATRIX_H +#define EXAMPLES_HELLO_WORLD_GLES_MATRIX_H + +/* Copyright (c) 2012 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** @file matrix.cc + * Implements simple matrix manipulation functions. + */ + +//----------------------------------------------------------------------------- +#define _USE_MATH_DEFINES 1 +#include <limits.h> +#include <math.h> +#include <GLES2/gl2.h> + +typedef GLfloat Matrix_t[16]; + +/// Since GLES2 doesn't have all the nifty matrix transform functions that GL +/// has, we emulate some of them here for the sake of sanity from: +/// http://www.opengl.org/wiki/GluPerspective_code +void glhFrustumf2(Matrix_t mat, GLfloat left, GLfloat right, GLfloat bottom, + GLfloat top, GLfloat znear, GLfloat zfar); + +void glhPerspectivef2(Matrix_t mat, GLfloat fovyInDegrees, + GLfloat aspectRatio, GLfloat znear, GLfloat zfar); + + +void identity_matrix(Matrix_t mat); +void multiply_matrix(const Matrix_t a, const Matrix_t b, Matrix_t mat); +void rotate_matrix(GLfloat x_deg, GLfloat y_deg, GLfloat z_deg, Matrix_t mat); +void translate_matrix(GLfloat x, GLfloat y, GLfloat z, Matrix_t mat); + +#endif // EXAMPLES_HELLO_WORLD_GLES_MATRIX_H + diff --git a/native_client_sdk/src/examples/hello_world_instance3d/vertex_shader_es2.vert b/native_client_sdk/src/examples/hello_world_instance3d/vertex_shader_es2.vert new file mode 100644 index 0000000..da616cb --- /dev/null +++ b/native_client_sdk/src/examples/hello_world_instance3d/vertex_shader_es2.vert @@ -0,0 +1,12 @@ +uniform mat4 a_MVP; +attribute vec2 a_texCoord; +attribute vec3 a_color; +attribute vec4 a_position; +varying vec3 v_color; +varying vec2 v_texCoord; +void main() +{ + gl_Position = a_MVP * a_position; + v_color = a_color; + v_texCoord = a_texCoord; +}
\ No newline at end of file diff --git a/native_client_sdk/src/libraries/nacl_mounts/Makefile b/native_client_sdk/src/libraries/nacl_mounts/Makefile index 5597f0c..6c9714e 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/Makefile +++ b/native_client_sdk/src/libraries/nacl_mounts/Makefile @@ -16,7 +16,7 @@ # to override this, specify TOOLCHAIN=newlib|glibc or CONFIG=Debug|Release on # the make command-line or in this file prior to including common.mk. The # toolchain we use by default will be the first valid one listed -VALID_TOOLCHAINS:=newlib glibc win +VALID_TOOLCHAINS:=newlib glibc pnacl win # diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc index 32a12e4..1e67faf 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc +++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc @@ -123,8 +123,9 @@ int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) { } int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) { - *nread = ki_read(fd, buf, count); - return (*nread < 0) ? errno : 0; + ssize_t signed_nread = ki_read(fd, buf, count); + *nread = static_cast<size_t>(signed_nread); + return (signed_nread < 0) ? errno : 0; } int remove(const char* path) { @@ -157,8 +158,9 @@ int unlink(const char* path) { } int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) { - *nwrote = ki_write(fd, buf, count); - return (*nwrote < 0) ? errno : 0; + ssize_t signed_nwrote = ki_write(fd, buf, count); + *nwrote = static_cast<size_t>(signed_nwrote); + return (signed_nwrote < 0) ? errno : 0; } diff --git a/native_client_sdk/src/libraries/nacl_mounts/library.dsc b/native_client_sdk/src/libraries/nacl_mounts/library.dsc index 83e95eb..0e76844 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/library.dsc +++ b/native_client_sdk/src/libraries/nacl_mounts/library.dsc @@ -1,7 +1,7 @@ { # Disabled pnacl for now because it warns on using the language extension # typeof(...) - 'TOOLS': ['newlib', 'glibc', 'win'], + 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'], 'SEARCH': [ '.', 'pepper', diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_http.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_http.cc index 06dc954..bd5fc40 100644 --- a/native_client_sdk/src/libraries/nacl_mounts/mount_http.cc +++ b/native_client_sdk/src/libraries/nacl_mounts/mount_http.cc @@ -82,7 +82,6 @@ StringMap_t ParseHeaders(const char* headers, int32_t headers_length) { // Found value. value.assign(start, &headers[i] - start); result[key] = value; - start = &headers[i + 1]; state = FINDING_KEY; } diff --git a/native_client_sdk/src/libraries/ppapi_main/Makefile b/native_client_sdk/src/libraries/ppapi_main/Makefile index fb16a49..dbe8852 100644 --- a/native_client_sdk/src/libraries/ppapi_main/Makefile +++ b/native_client_sdk/src/libraries/ppapi_main/Makefile @@ -16,7 +16,7 @@ # to override this, specify TOOLCHAIN=newlib|glibc or CONFIG=Debug|Release on # the make command-line or in this file prior to including common.mk. The # toolchain we use by default will be the first valid one listed -VALID_TOOLCHAINS:=newlib glibc +VALID_TOOLCHAINS:=newlib glibc pnacl # @@ -40,7 +40,8 @@ TARGET=ppapi_main # # List of sources to compile # -SOURCES:=ppapi_main.cc ppapi_instance.cc +SOURCES:=ppapi_main.cc ppapi_instance.cc ppapi_instance3d.cc +SOURCES+=ppapi_queue.cc # # Use the compile macro for each source. # diff --git a/native_client_sdk/src/libraries/ppapi_main/library.dsc b/native_client_sdk/src/libraries/ppapi_main/library.dsc index 65e1c0f..ea13689 100644 --- a/native_client_sdk/src/libraries/ppapi_main/library.dsc +++ b/native_client_sdk/src/libraries/ppapi_main/library.dsc @@ -1,23 +1,25 @@ { 'TOOLS': ['newlib', 'glibc'], - 'SEARCH': [ - '.', - ], 'TARGETS': [ { 'NAME' : 'ppapi_main', 'TYPE' : 'lib', 'SOURCES' : [ "ppapi_instance.cc", + "ppapi_instance3d.cc", "ppapi_main.cc", + "ppapi_queue.cc", ], } ], 'HEADERS': [ { 'FILES': [ + "ppapi_event.h", "ppapi_instance.h", + "ppapi_instance3d.h", "ppapi_main.h", + "ppapi_queue.h", ], 'DEST': 'include/ppapi_main', }, diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_event.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_event.h new file mode 100644 index 0000000..6d222db --- /dev/null +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_event.h @@ -0,0 +1,81 @@ +// Copyright (c) 2013 The Chromium 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 PPAPI_MAIN_PPAPI_EVENT_H_ +#define PPAPI_MAIN_PPAPI_EVENT_H_ + +#include "ppapi/c/pp_input_event.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_touch_point.h" +#include "ppapi/c/ppb_input_event.h" + +#include "utils/macros.h" + +EXTERN_C_BEGIN + +/* + * Event Structures + * + * The following event structures are based on the equivilent structs + * defined in ppapi/c/ppb_input_event.h. + * + */ + +// Generic Event +typedef struct { + PP_InputEvent_Type event_type; + PP_TimeTicks time_ticks; + uint32_t modifiers; +} PPAPIEvent; + + +// Key Code Up/Down +typedef struct { + PPAPIEvent event; + + uint32_t key_code; +} PPAPIKeyEvent; + + +// Cooked Character Event +typedef struct { + PPAPIEvent event; + + char text[5]; +} PPAPICharEvent; + + +// Mouse Event +typedef struct { + PPAPIEvent event; + + PP_InputEvent_MouseButton button; + struct PP_Point location; + struct PP_Point delta; +} PPAPIMouseEvent; + + +// Wheel Event +typedef struct { + PPAPIEvent event; + + PP_InputEvent_MouseButton button; + struct PP_FloatPoint delta; + uint32_t by_page; +} PPAPIWheelEvent; + + +// Touch Event +#define MAX_TOUCH_POINTS 4 +typedef struct { + PPAPIEvent event; + + uint32_t point_count; + struct PP_TouchPoint points[MAX_TOUCH_POINTS]; +} PPAPITouchEvent; + +EXTERN_C_END + +#endif // PPAPI_MAIN_PPAPI_EVENT_H_
\ No newline at end of file diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.cc index 7f4c1d2..5bd92d2 100644 --- a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.cc +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.cc @@ -5,6 +5,7 @@ #include <fcntl.h> #include <pthread.h> #include <stdio.h> +#include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> @@ -18,21 +19,30 @@ #include "nacl_mounts/nacl_mounts.h" #include "ppapi/cpp/input_event.h" +#include "ppapi/cpp/message_loop.h" #include "ppapi/cpp/rect.h" #include "ppapi/cpp/size.h" +#include "ppapi/cpp/touch_point.h" #include "ppapi/cpp/var.h" +#include "ppapi_main/ppapi_event.h" #include "ppapi_main/ppapi_instance.h" #include "ppapi_main/ppapi_main.h" +PPAPIInstance* PPAPI_GetInstance() { + return static_cast<PPAPIInstance*>(PPAPI_GetInstanceObject()); +} + struct StartInfo { + PPAPIInstance* inst_; uint32_t argc_; const char** argv_; }; -static void* StartMain(void *info) { +void* PPAPIInstance::StartMain(void *info) { StartInfo* si = static_cast<StartInfo*>(info); + si->inst_->main_loop_.AttachToCurrentThread(); if (NULL != info) { ppapi_main(si->argc_, si->argv_); @@ -47,21 +57,24 @@ static void* StartMain(void *info) { const char *argv[] = { "NEXE", NULL }; ppapi_main(1, argv); } + return NULL; } PPAPIInstance::PPAPIInstance(PP_Instance instance, const char *args[]) : pp::Instance(instance), + main_loop_(this), has_focus_(false) { - while (*args) { std::string key = *args++; std::string val = *args++; properties_[key] = val; } - RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); - RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); + RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | + PP_INPUTEVENT_CLASS_KEYBOARD | + PP_INPUTEVENT_CLASS_WHEEL | + PP_INPUTEVENT_CLASS_TOUCH); } PPAPIInstance::~PPAPIInstance() { @@ -72,13 +85,14 @@ bool PPAPIInstance::Init(uint32_t arg, const char* argv[]) { StartInfo* si = new StartInfo; + si->inst_ = this; si->argc_ = 1; si->argv_ = new const char *[arg*2+1]; si->argv_[0] = NULL; for (uint32_t i=0; i < arg; i++) { // If we start with PM prefix set the instance argument map - if (0 == strncmp(argn[i], "PM_", 3)) { + if (0 == strncmp(argn[i], "pm_", 3)) { std::string key = argn[i]; std::string val = argv[i]; properties_[key] = val; @@ -125,7 +139,7 @@ bool PPAPIInstance::Init(uint32_t arg, } const char* PPAPIInstance::GetProperty(const char* key, const char* def) { - PropteryMap_t::iterator it = properties_.find(key); + PropertyMap_t::iterator it = properties_.find(key); if (it != properties_.end()) { return it->second.c_str(); } @@ -133,54 +147,115 @@ const char* PPAPIInstance::GetProperty(const char* key, const char* def) { } bool PPAPIInstance::ProcessProperties() { - const char* stdin_path = GetProperty("PM_STDIO", "/dev/null"); - const char* stdout_path = GetProperty("PM_STDOUT", "/dev/tty"); - const char* stderr_path = GetProperty("PM_STDERR", "/dev/console3"); + const char* stdin_path = GetProperty("pm_stdio", "/dev/null"); + const char* stdout_path = GetProperty("pm_stdout", "/dev/console1"); + const char* stderr_path = GetProperty("pm_stderr", "/dev/console3"); + const char* queue_size = GetProperty("pm_queue_size", "1024"); + + // Force a miniumum size of 4 + uint32_t queue_size_int = atoi(queue_size); + if (queue_size_int < 4) queue_size_int = 4; + event_queue_.SetSize(queue_size_int); nacl_mounts_init_ppapi(PPAPI_GetInstanceId(), PPAPI_GetInterface); - int f1 = open(stdin_path, O_RDONLY); - int f2 = open(stdout_path, O_WRONLY); - int f3 = open(stderr_path, O_WRONLY); + int fd0 = open(stdin_path, O_RDONLY); + int fd1 = open(stdout_path, O_WRONLY); + int fd2 = open(stderr_path, O_WRONLY); - return true; + return (fd0 == 0) && (fd1 == 1) && (fd2 == 2); } -void PPAPIInstance::HandleMessage(const pp::Var& message) { -} +void PPAPIInstance::HandleMessage(const pp::Var& message) {} bool PPAPIInstance::HandleInputEvent(const pp::InputEvent& event) { + PPAPIEvent* event_ptr; + + // Remove a stale message if one is available + event_ptr = static_cast<PPAPIEvent*>(event_queue_.RemoveStaleMessage()); + delete event_ptr; + switch (event.GetType()) { - case PP_INPUTEVENT_TYPE_UNDEFINED: - break; case PP_INPUTEVENT_TYPE_MOUSEDOWN: - // If we do not yet have focus, return true. In return Chrome will give - // focus to the NaCl embed. - return !has_focus_; - break; - case PP_INPUTEVENT_TYPE_KEYDOWN: - break; case PP_INPUTEVENT_TYPE_MOUSEUP: case PP_INPUTEVENT_TYPE_MOUSEMOVE: case PP_INPUTEVENT_TYPE_MOUSEENTER: - case PP_INPUTEVENT_TYPE_MOUSELEAVE: - case PP_INPUTEVENT_TYPE_WHEEL: + case PP_INPUTEVENT_TYPE_MOUSELEAVE: { + pp::MouseInputEvent mouse_event(event); + PPAPIMouseEvent* mouse_ptr = new PPAPIMouseEvent; + mouse_ptr->button = mouse_event.GetButton(); + mouse_ptr->location = mouse_event.GetPosition().pp_point(); + mouse_ptr->delta = mouse_event.GetMovement().pp_point(); + event_ptr = &mouse_ptr->event; + break; + } + + case PP_INPUTEVENT_TYPE_WHEEL: { + pp::WheelInputEvent wheel_event(event); + PPAPIWheelEvent* wheel_ptr = new PPAPIWheelEvent; + wheel_ptr->by_page = + static_cast<uint32_t>(wheel_event.GetScrollByPage()); + wheel_ptr->delta = wheel_event.GetDelta().pp_float_point(); + event_ptr = &wheel_ptr->event; + break; + } + + case PP_INPUTEVENT_TYPE_CHAR: { + pp::KeyboardInputEvent key_event(event); + PPAPICharEvent* char_ptr = new PPAPICharEvent; + strncpy(char_ptr->text, + key_event.GetCharacterText().DebugString().c_str(), + sizeof(char_ptr->text)); + event_ptr = &char_ptr->event; + break; + } + case PP_INPUTEVENT_TYPE_RAWKEYDOWN: - case PP_INPUTEVENT_TYPE_KEYUP: - case PP_INPUTEVENT_TYPE_CHAR: - case PP_INPUTEVENT_TYPE_CONTEXTMENU: - case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START: - case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE: - case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END: - case PP_INPUTEVENT_TYPE_IME_TEXT: + case PP_INPUTEVENT_TYPE_KEYDOWN: + case PP_INPUTEVENT_TYPE_KEYUP: { + pp::KeyboardInputEvent key_event(event); + PPAPIKeyEvent* key_ptr = new PPAPIKeyEvent; + key_ptr->key_code = key_event.GetKeyCode(); + event_ptr = &key_ptr->event; + break; + } + case PP_INPUTEVENT_TYPE_TOUCHSTART: case PP_INPUTEVENT_TYPE_TOUCHMOVE: case PP_INPUTEVENT_TYPE_TOUCHEND: - case PP_INPUTEVENT_TYPE_TOUCHCANCEL: + case PP_INPUTEVENT_TYPE_TOUCHCANCEL: { + pp::TouchInputEvent touch_event(event); + PPAPITouchEvent* touch_ptr = new PPAPITouchEvent; + touch_ptr->point_count = + touch_event.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES); + for (uint32_t cnt = 0; cnt < touch_ptr->point_count; cnt++) { + pp::TouchPoint *pnt = (pp::TouchPoint*) &touch_ptr->points[cnt]; + *pnt = touch_event.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES ,cnt); + } + event_ptr = &touch_ptr->event; + break; + } + default: + fprintf(stderr, "Unhandled event type %d\n", event.GetType()); return false; } - return false; + + event_ptr->event_type = event.GetType(); + event_ptr->time_ticks = event.GetTimeStamp(); + event_ptr->modifiers = event.GetModifiers(); + if (!event_queue_.AddNewMessage(event_ptr)) { + printf("Warning: Event Queue is full, dropping message.\n"); + } + return true; +} + +PPAPIEvent* PPAPIInstance::AcquireInputEvent() { + return static_cast<PPAPIEvent*>(event_queue_.AcquireTopMessage()); +} + +void PPAPIInstance::ReleaseInputEvent(PPAPIEvent* event) { + event_queue_.ReleaseTopMessage(event); } void PPAPIInstance::DidChangeView(const pp::View&) { diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.h index 279388e..47be29b 100644 --- a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.h +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.h @@ -10,8 +10,12 @@ #include "ppapi/c/pp_instance.h" #include "ppapi/cpp/fullscreen.h" #include "ppapi/cpp/instance.h" +#include "ppapi/cpp/message_loop.h" -typedef std::map<std::string, std::string> PropteryMap_t; +#include "ppapi_main/ppapi_event.h" +#include "ppapi_main/ppapi_queue.h" + +typedef std::map<std::string, std::string> PropertyMap_t; class PPAPIInstance : public pp::Instance { public: @@ -33,7 +37,18 @@ class PPAPIInstance : public pp::Instance { // Called by the browser to handle incoming input events. virtual bool HandleInputEvent(const pp::InputEvent& event); + // Accessors for the PPAPIQueue object. Use Acquire to fetch the top + // event if one is available, then release when done. Events must be + // acquired and released one at a time. + virtual PPAPIEvent* AcquireInputEvent(); + virtual void ReleaseInputEvent(PPAPIEvent* event); + + static PPAPIInstance* GetInstance(); + protected: + // Called to launch ppapi_main + static void* StartMain(void *start_info); + // Called by Init to processes default and embed tag arguments prior to // launching the 'ppapi_main' thread. virtual bool ProcessProperties(); @@ -42,7 +57,9 @@ class PPAPIInstance : public pp::Instance { const char* GetProperty(const char* key, const char* def = NULL); private: - PropteryMap_t properties_; + pp::MessageLoop main_loop_; + PropertyMap_t properties_; + PPAPIQueue event_queue_; bool has_focus_; }; diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.cc new file mode 100644 index 0000000..068f39f --- /dev/null +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.cc @@ -0,0 +1,232 @@ +// Copyright (c) 2012 The Chromium 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 <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <cstdlib> +#include <cstring> +#include <map> +#include <string> +#include <vector> + +#include "nacl_mounts/nacl_mounts.h" + +#include "ppapi/cpp/fullscreen.h" +#include "ppapi/cpp/graphics_3d.h" +#include "ppapi/cpp/input_event.h" +#include "ppapi/cpp/message_loop.h" +#include "ppapi/cpp/mouse_lock.h" +#include "ppapi/cpp/rect.h" +#include "ppapi/cpp/size.h" +#include "ppapi/cpp/var.h" + +#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h" +#include "ppapi/lib/gl/include/GLES2/gl2.h" + +#include "ppapi/utility/completion_callback_factory.h" + +#include "ppapi_main/ppapi_instance.h" +#include "ppapi_main/ppapi_instance3d.h" +#include "ppapi_main/ppapi_main.h" + + +static const uint32_t kReturnKeyCode = 13; + + +void* PPAPI_CreateInstance3D(PP_Instance inst, const char *args[]) { + return static_cast<void*>(new PPAPIInstance3D(inst, args)); +} + + +int32_t *PPAPIGet3DAttribs(uint32_t width, uint32_t height) { + static int32_t attribs[] = { + PP_GRAPHICS3DATTRIB_WIDTH, 0, + PP_GRAPHICS3DATTRIB_HEIGHT, 0, + PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, + PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24, + PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8, + PP_GRAPHICS3DATTRIB_SAMPLES, 0, + PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, + PP_GRAPHICS3DATTRIB_NONE + }; + + attribs[1] = width; + attribs[3] = height; + + printf("Building attribs for %dx%d.\n", width, height); + return attribs; +} + +void PPAPIBuildContext(uint32_t width, uint32_t height) { + glViewport(0, 0, width, height); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + printf("Built Context %d, %d.\n", width, height); +} + + +PPAPIInstance3D* PPAPIInstance3D::GetInstance3D() { + return static_cast<PPAPIInstance3D*>(PPAPI_GetInstanceObject()); +} + + +void *PPAPIInstance3D::RenderLoop(void *this_ptr) { + PPAPIInstance3D *pInst = static_cast<PPAPIInstance3D*>(this_ptr); + pInst->render_loop_.AttachToCurrentThread(); + pInst->render_loop_.Run(); + return NULL; +} + + +void PPAPIInstance3D::Swapped(int result) { + if (result != 0) { + printf("Swapped result=%d.\n", result); + } + + if (is_context_bound_) { + PPAPIRender(size_.width(), size_.height()); + int result; + result = device_context_.SwapBuffers(callback_factory_.NewCallback( + &PPAPIInstance3D::Swapped)); + if (result == PP_OK_COMPLETIONPENDING) return; + printf("Failed swap with %d.\n", result); + } + + // Failed to draw, so add a callback for the future. + pp::MessageLoop::GetCurrent().PostWork(callback_factory_.NewCallback( + &PPAPIInstance3D::Swapped), 100); +} + +void PPAPIInstance3D::BuildContext(int32_t result, const pp::Size& new_size) { + printf("Building context.\n"); + + // If already bound, try to resize to avoid the need to rebuild the context. + if (is_context_bound_) { + // If the size is correct, then just skip this request. + if (new_size == size_) { + printf("Skipped building context, same size as bound.\n"); + return; + } + int err = device_context_.ResizeBuffers(new_size.width(), + new_size.height()); + + // Resized the context, we are done + if (err == PP_OK) { + size_ = new_size; + fprintf(stderr, "Resized context from %dx%d to %dx%d", + size_.width(), size_.height(), new_size.width(), + new_size.height()); + PPAPIBuildContext(size_.width(), size_.height()); + return; + } + + // Failed to resize, fall through and start from scratch + fprintf(stderr, "Failed to resize buffer from %dx%d to %dx%d", + size_.width(), size_.height(), new_size.width(), new_size.height()); + + is_context_bound_ = false; + } + + printf("Calling create context....\n"); + size_ = new_size; + device_context_ = pp::Graphics3D(this, PPAPIGet3DAttribs(size_.width(), + size_.height())); + printf("Got Context!\n"); + is_context_bound_ = BindGraphics(device_context_); + printf("Context is bound=%d\n", is_context_bound_); + + // The the context regardless to make sure we have a valid one + glSetCurrentContextPPAPI(device_context_.pp_resource()); + if (is_context_bound_) { + PPAPIBuildContext(size_.width(), size_.height()); + device_context_.SwapBuffers(callback_factory_.NewCallback( + &PPAPIInstance3D::Swapped)); + } else { + fprintf(stderr, "Failed to bind context for %dx%d.\n", size_.width(), + size_.height()); + } +} + +PPAPIInstance3D::PPAPIInstance3D(PP_Instance instance, const char *args[]) + : PPAPIInstance(instance, args), + mouse_locked_(false), + callback_factory_(this), + fullscreen_(this), + is_context_bound_(false), + was_fullscreen_(false), + render_loop_(this), + main_thread_3d_(true) { + glInitializePPAPI(pp::Module::Get()->get_browser_interface()); +} + + +PPAPIInstance3D::~PPAPIInstance3D() { + if (is_context_bound_) { + is_context_bound_ = false; + // Cleanup code? + } +} + +bool PPAPIInstance3D::Init(uint32_t arg, + const char* argn[], + const char* argv[]) { + if (!PPAPIInstance::Init(arg, argn, argv)) { + return false; + } + + for (uint32_t a=0; a < arg; a++) { + printf("%s=%s\n", argn[a], argv[a]); + } + + const char *use_main = GetProperty("pm_main3d", "true"); + main_thread_3d_ = !strcasecmp(use_main, "true"); + printf("Using 3D on main thread = %s.\n", use_main); + if (!main_thread_3d_) { + pthread_t render_thread; + int ret = pthread_create(&render_thread, NULL, RenderLoop, + static_cast<void*>(this)); + return ret == 0; + } + return true; +} + +void PPAPIInstance3D::DidChangeView(const pp::View& view) { + pp::Size new_size = view.GetRect().size(); + printf("View changed: %dx%d\n", new_size.width(), new_size.height()); + + // Build or update the 3D context when the view changes. + if (main_thread_3d_) { + // If using the main thread, update the context immediately + BuildContext(0, new_size); + } else { + // If using a seperate thread, then post the message so we can build the + // context on the correct thread. + render_loop_.PostWork(callback_factory_.NewCallback( + &PPAPIInstance3D::BuildContext, new_size)); + } +} + +bool PPAPIInstance3D::ToggleFullscreen() { + // Ignore switch if in transition + if (!is_context_bound_) + return false; + + if (fullscreen_.IsFullscreen()) { + if (!fullscreen_.SetFullscreen(false)) { + printf("Could not leave fullscreen mode\n"); + return false; + } + } else { + if (!fullscreen_.SetFullscreen(true)) { + printf("Could not enter fullscreen mode\n"); + return false; + } + } + return true; +} diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.h new file mode 100644 index 0000000..8c392809 --- /dev/null +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.h @@ -0,0 +1,59 @@ +// Copyright (c) 2012 The Chromium 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 PPAPI_MAIN_PPAPI_INSTANCE3D_H_ +#define PPAPI_MAIN_PPAPI_INSTANCE3D_H_ + +#include <map> + +#include "ppapi/c/pp_instance.h" +#include "ppapi/cpp/fullscreen.h" +#include "ppapi/cpp/graphics_3d.h" +#include "ppapi/cpp/input_event.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/message_loop.h" +#include "ppapi/cpp/mouse_lock.h" +#include "ppapi/utility/completion_callback_factory.h" + +#include "ppapi_main/ppapi_instance.h" + + +class PPAPIInstance3D : public PPAPIInstance { + public: + PPAPIInstance3D(PP_Instance instance, const char *args[]); + virtual ~PPAPIInstance3D(); + + // Called during initialization + virtual bool Init(uint32_t arg, const char* argn[], const char* argv[]); + + // Called whenever the in-browser window changes size. + virtual void DidChangeView(const pp::View& view); + + // Called when we need to rebuild the context + virtual void BuildContext(int32_t result, const pp::Size& new_size); + + // Called whenever a swap takes place + virtual void Swapped(int result); + + // Toggle in and out of Fullscreen mode + virtual bool ToggleFullscreen(); + + static PPAPIInstance3D* GetInstance3D(); + + protected: + static void *RenderLoop(void *this_ptr); + + pp::CompletionCallbackFactory<PPAPIInstance3D> callback_factory_; + pp::Fullscreen fullscreen_; + pp::Graphics3D device_context_; + pp::Size size_; + pp::MessageLoop render_loop_; + bool is_context_bound_; + bool was_fullscreen_; + bool mouse_locked_; + bool main_thread_3d_; +}; + + +#endif // PPAPI_MAIN_PPAPI_INSTANCE3D_H_ diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_main.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_main.cc index c3c7392..3d666c9 100644 --- a/native_client_sdk/src/libraries/ppapi_main/ppapi_main.cc +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_main.cc @@ -10,6 +10,7 @@ #include "ppapi/cpp/module.h" #include "ppapi_main/ppapi_instance.h" +#include "ppapi_main/ppapi_instance3d.h" #include "ppapi_main/ppapi_main.h" @@ -17,6 +18,10 @@ static pp::Instance* s_Instance = NULL; // Helpers to access PPAPI interfaces +void* PPAPI_GetInstanceObject() { + return s_Instance; +} + PP_Instance PPAPI_GetInstanceId() { return s_Instance->pp_instance(); } @@ -25,11 +30,19 @@ const void* PPAPI_GetInterface(const char *name) { return pp::Module::Get()->GetBrowserInterface(name); } - void* PPAPI_CreateInstance(PP_Instance inst, const char *args[]) { return static_cast<void*>(new PPAPIInstance(inst, args)); } +PPAPIEvent* PPAPI_AcquireEvent() { + return static_cast<PPAPIInstance*>(s_Instance)->AcquireInputEvent(); +} + +void PPAPI_ReleaseEvent(PPAPIEvent* event) { + static_cast<PPAPIInstance*>(s_Instance)->ReleaseInputEvent(event); +} + + /// 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". diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_main.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_main.h index 01958384..7f653d1 100644 --- a/native_client_sdk/src/libraries/ppapi_main/ppapi_main.h +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_main.h @@ -7,6 +7,8 @@ #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_module.h" +#include "ppapi_main/ppapi_event.h" + #include "utils/macros.h" EXTERN_C_BEGIN @@ -18,6 +20,7 @@ int ppapi_main(int argc, const char *argv[]); void* UserCreateInstance(PP_Instance inst); // Helpers to access PPAPI interfaces +void* PPAPI_GetInstanceObject(); PP_Instance PPAPI_GetInstanceId(); const void* PPAPI_GetInterface(const char *name); @@ -26,13 +29,23 @@ void* PPAPI_CreateInstance(PP_Instance inst, const char *args[]); void* PPAPI_CreateInstance2D(PP_Instance inst, const char *args[]); void* PPAPI_CreateInstance3D(PP_Instance inst, const char *args[]); +// Event APIs +PPAPIEvent* PPAPI_AcquireEvent(); +void PPAPI_ReleaseEvent(PPAPIEvent* event); + + +// Functions for 3D instances +int32_t *PPAPIGet3DAttribs(uint32_t width, uint32_t height); +void PPAPIBuildContext(uint32_t width, uint32_t height); +void PPAPIRender(uint32_t width, uint32_t height); + EXTERN_C_END #define PPAPI_MAIN_DEFAULT_ARGS \ { \ - "PM_STDIN", "/dev/null", \ - "PM_STDIO", "/dev/console0", \ - "PM_STDERR", "/dev/console3", \ + "pm_stdin", "/dev/null", \ + "pm_stdout", "/dev/console0", \ + "pm_stderr", "/dev/console3", \ NULL, NULL \ } @@ -46,6 +59,9 @@ void* UserCreateInstance(PP_Instance inst) { \ #define PPAPI_MAIN_WITH_DEFAULT_ARGS \ PPAPI_MAIN_USE(PPAPI_CreateInstance, PPAPI_MAIN_DEFAULT_ARGS) +#define PPAPI_MAIN_3D_WITH_DEFAULT_ARGS \ + PPAPI_MAIN_USE(PPAPI_CreateInstance3D, PPAPI_MAIN_DEFAULT_ARGS) + #define PPAPI_MAIN_WITH_ARGS(args) \ PPAPI_MAIN_USE(PPAPI_CreateInstance, args) diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.cc new file mode 100644 index 0000000..ff5ed38 --- /dev/null +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2013 The Chromium 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 <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "ppapi_main/ppapi_queue.h" + +PPAPIQueue::PPAPIQueue() + : read_(0), + write_(0), + freed_(0), + size_(0), + array_(NULL) { } + +PPAPIQueue::~PPAPIQueue() { + // Messages may be leaked if the queue is not empty. + assert(read_ == write_); + + delete[] array_; +} + +bool PPAPIQueue::SetSize(uint32_t queue_size) { + assert(queue_size > 0); + + if (array_) return false; + + array_ = new void*[queue_size]; + size_ = queue_size; + + memset(array_, 0, sizeof(void*) * queue_size); + return true; +} + +bool PPAPIQueue::AddNewMessage(void* msg) { + // Writting a NULL message is illegal + assert(array_ != NULL); + assert(msg != NULL); + + // If the slot not empty, the queue must be full. Calling RemoveStaleMessage + // may create space by freeing messages that have already been read. + if (array_[write_] != NULL) return false; + + // Write to the spot + array_[write_] = msg; + + // Fence to make sure the payload and payload pointer are visible. + // Since Win32 is x86 which provides ordered writes, we don't need to + // synchronize in that case. +#ifndef WIN32 + __sync_synchronize(); +#endif + + // Increment the write pointer, to signal it's readable. + write_ = (write_ + 1) % size_; + return true; +} + +void* PPAPIQueue::RemoveStaleMessage() { + assert(array_ != NULL); + + // If freed and read pointer are equal, this hasn't been read yet + if (freed_ == read_) return NULL; + + assert(array_[freed_] != NULL); + + void* ret = array_[freed_]; + array_[freed_] = NULL; + + freed_ = (freed_ + 1) % size_; + return ret; +} + +void* PPAPIQueue::AcquireTopMessage() { + // Assert that we aren't already reading a message. + assert(last_msg_ == NULL); + + // If read and write pointers are equal, the queue is empty. + if (read_ == write_) return NULL; + + // Track the last message to look for illegal API use. + last_msg_ = array_[read_]; + return last_msg_; +} + +void PPAPIQueue::ReleaseTopMessage(void* msg) { + // Verify we currently acquire message. + assert(msg != NULL); + assert(msg == last_msg_); + + last_msg_ = NULL; + + // Signal that the message can be freed. + read_ = (read_ + 1) % size_; +} diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.h new file mode 100644 index 0000000..b40c3ec --- /dev/null +++ b/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.h @@ -0,0 +1,84 @@ +// Copyright (c) 2013 The Chromium 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 PPAPI_MAIN_PPAPI_QUEUE_H +#define PPAPI_MAIN_PPAPI_QUEUE_H + +#include <stdint.h> + +// +// PPAPIQueue +// +// PPAPIQueue is a single producer/single consumer lockless queue. This +// implementation is PPAPI friendly because it prevents the main thread from +// ever needing to lock. In addition, allocation and destruction of messages +// happens on the same thread, allowing for lockless message allocation as well. +// +// Messages pass through four states in order: +// AddNewMessage - The message is added to the queue by the producer +// and the memory is fenced to ensure it is visible. Once the fence +// returns, the write pointer is incremented to signal it's available to +// the consumer. NOTE: NULL messages are illegal. +// +// AcquireTopMessage - Next the message is acquired by the consumer thread. +// At this point, the consumer is considered to be examining the payload so +// we do not increment the read pointer yet to prevent deletion. NOTE: it +// is illegal to acquire the next message until the previous one is released. +// +// ReleaseTopMessage - Now the consumer signals that it is no longer looking +// at the message by incremented the read pointer. The producer is free to +// release or reuse the payload. +// +// RemoveStaleMessage - The message is no longer visible to the consumer, so +// it is returned to the producer to be reused or destroyed. It's location +// in the queue is set to NULL to signal that a new message may be added in +// that slot. +// +class PPAPIQueue { + public: + PPAPIQueue(); + ~PPAPIQueue(); + + // + // Producer API + // + // First, the producer must set the queue size before any operation can + // take place. Next, before adding a message, clear space in the queue, + // by removing stale messages. Adding a new message will return TRUE if + // space is available, otherwise FALSE is returned and it's up to the + // application developer to decide what to do. + // + bool SetSize(uint32_t queue_size); + bool AddNewMessage(void* msg); + void* RemoveStaleMessage(); + + // + // Consumer API + // + // The reader will attempt to Acquire the top message, if one is not + // available NULL will be returned. Once the consumer is done with the + // message, ReleaseTopMessage is called to signal that the payload is no + // longer visible to the consumer and can be recycled or destroyed. + // Since messages are freed in order, it is recquired that messages are + // consumed in order. For this reason, it is illegal to call Acquire again + // after a non-NULL message pointer is returned, until Release is called on + // the old message. This means the consumer can only look at one message + // at a time. To look at multiple messages at once, the consumer would + // need to make a copy and release the top message. + // + void* AcquireTopMessage(); + void ReleaseTopMessage(void* msg); + + private: + uint32_t read_; + uint32_t write_; + uint32_t freed_; + uint32_t size_; + void* last_msg_; + void** array_; +}; + + +#endif // PPAPI_MAIN_PPAPI_QUEUE_H
\ No newline at end of file |