Chromium Code Reviews| Index: native_client_sdk/src/examples/api/graphics_3d/graphics_3d.cc |
| diff --git a/native_client_sdk/src/examples/api/graphics_3d/graphics_3d.cc b/native_client_sdk/src/examples/api/graphics_3d/graphics_3d.cc |
| index 4c852666bd1ec9868beeb4d84ab51fd3fe88dadb..d28f5a5f299416bac5ab63e5ea2b81803703e36b 100644 |
| --- a/native_client_sdk/src/examples/api/graphics_3d/graphics_3d.cc |
| +++ b/native_client_sdk/src/examples/api/graphics_3d/graphics_3d.cc |
| @@ -1,616 +1,502 @@ |
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// 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. |
| -//----------------------------------------------------------------------------- |
| -// The spinning Cube |
| -//----------------------------------------------------------------------------- |
| - |
| -#define _USE_MATH_DEFINES 1 |
| -#include <limits.h> |
| +#include <GLES2/gl2.h> |
| #include <math.h> |
| -#include <stdarg.h> |
| #include <stddef.h> |
| +#include <stdint.h> |
| #include <stdio.h> |
| -#include <stdlib.h> |
| #include <string.h> |
| -#include "ppapi/c/pp_completion_callback.h" |
| -#include "ppapi/c/pp_errors.h" |
| -#include "ppapi/c/pp_graphics_3d.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_core.h" |
| -#include "ppapi/c/ppb_graphics_3d.h" |
| -#include "ppapi/c/ppb_instance.h" |
| -#include "ppapi/c/ppb_messaging.h" |
| -#include "ppapi/c/ppb_opengles2.h" |
| -#include "ppapi/c/ppb_url_loader.h" |
| -#include "ppapi/c/ppb_url_request_info.h" |
| -#include "ppapi/c/ppb_var.h" |
| -#include "ppapi/c/ppp.h" |
| -#include "ppapi/c/ppp_instance.h" |
| -#include "ppapi/c/ppp_messaging.h" |
| - |
| -#include "ppapi/c/ppp_graphics_3d.h" |
| -#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h" |
| - |
| -#include <GLES2/gl2.h> |
| #include "matrix.h" |
| +#include "ppapi/cpp/graphics_3d.h" |
| +#include "ppapi/cpp/instance.h" |
| +#include "ppapi/cpp/module.h" |
| +#include "ppapi/cpp/var.h" |
| +#include "ppapi/cpp/var_array.h" |
| +#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h" |
| +#include "ppapi/utility/completion_callback_factory.h" |
| -static PPB_Messaging* ppb_messaging_interface = NULL; |
| -static PPB_Var* ppb_var_interface = NULL; |
| -static PPB_Core* ppb_core_interface = NULL; |
| -static PPB_Graphics3D* ppb_g3d_interface = NULL; |
| -static PPB_Instance* ppb_instance_interface = NULL; |
| -static PPB_URLRequestInfo* ppb_urlrequestinfo_interface = NULL; |
| -static PPB_URLLoader* ppb_urlloader_interface = NULL; |
| - |
| -static PP_Instance g_instance; |
| -static PP_Resource g_context; |
| - |
| -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; |
| -int g_LoadCnt = 0; |
| - |
| -//----------------------------------------------------------------------------- |
| -// PROTOTYPES |
| -//----------------------------------------------------------------------------- |
| -void PostMessage(const char* fmt, ...); |
| -char* LoadFile(const char* fileName); |
| - |
| -void BuildQuad(Vertex* verts, int axis[3], float depth, float color[3]); |
| -Vertex* BuildCube(void); |
| - |
| -void InitGL(void); |
| -void InitProgram(void); |
| -void Render(void); |
| +#ifdef WIN32 |
| +#undef PostMessage |
| +// Allow 'this' in initializer list |
| +#pragma warning(disable : 4355) |
| +#endif |
| -static struct PP_Var CStrToVar(const char* str) { |
| - if (ppb_var_interface != NULL) { |
| - return ppb_var_interface->VarFromUtf8(str, strlen(str)); |
| - } |
| - return PP_MakeUndefined(); |
| -} |
| +extern const uint8_t kRLETextureData[]; |
| +extern const size_t kRLETextureDataLength; |
| -void PostMessage(const char* fmt, ...) { |
| - va_list args; |
| - va_start(args, fmt); |
| +namespace { |
| - char msg[4096]; |
| - vsnprintf(msg, sizeof(msg), fmt, args); |
| +const float kFovY = 45.0f; |
| +const float kZNear = 1.0f; |
| +const float kZFar = 10.0f; |
| +const float kCameraZ = -4.0f; |
| +const float kXAngleDelta = 2.0f; |
| +const float kYAngleDelta = 0.5f; |
| - if (ppb_messaging_interface) |
| - ppb_messaging_interface->PostMessage(g_instance, CStrToVar(msg)); |
| +const size_t kTextureDataLength = 128 * 128 * 3; // 128x128, 3 Bytes/pixel. |
| - va_end(args); |
| -} |
| +// The decompressed data is written here. |
| +uint8_t g_texture_data[kTextureDataLength]; |
| -void MainLoop(void* foo, int bar) { |
| - if (g_LoadCnt == 3) { |
| - InitProgram(); |
| - g_LoadCnt++; |
| - } |
| - if (g_LoadCnt > 3) { |
| - Render(); |
| - PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0); |
| - ppb_g3d_interface->SwapBuffers(g_context, cc); |
| - } else { |
| - PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0); |
| - ppb_core_interface->CallOnMainThread(0, cc, 0); |
| - } |
| -} |
| - |
| -void InitGL(void) { |
| - int32_t attribs[] = { |
| - 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_WIDTH, 640, |
| - PP_GRAPHICS3DATTRIB_HEIGHT, 480, |
| - PP_GRAPHICS3DATTRIB_NONE |
| +void DecompressTexture() { |
| + // The image is first encoded with a very simple RLE scheme: |
| + // <value0> <count0> <value1> <count1> ... |
| + // Because a <count> of 0 is useless, we use it to represent 256. |
| + // |
| + // It is then Base64 encoded to make it use only printable characters (it |
| + // stores more easily in a source file that way). |
| + // |
| + // To decompress, we have to reverse the process. |
| + static const uint8_t kBase64Decode[256] = { |
| + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, |
| + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, |
| + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, |
| + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
| + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, |
| }; |
| + const uint8_t* input = &kRLETextureData[0]; |
| + const uint8_t * const input_end = &kRLETextureData[kRLETextureDataLength]; |
| + uint8_t* output = &g_texture_data[0]; |
| + const uint8_t * const output_end = &g_texture_data[kTextureDataLength]; |
| + |
| + uint8_t decoded[4]; |
| + int decoded_count = 0; |
| + |
| + while (input < input_end || decoded_count > 0) { |
| + if (decoded_count < 2) { |
| + assert(input + 4 <= input_end); |
| + // Grab four base-64 encoded (6-bit) bytes. |
| + uint32_t data = 0; |
| + data |= (kBase64Decode[*input++] << 18); |
| + data |= (kBase64Decode[*input++] << 12); |
| + data |= (kBase64Decode[*input++] << 6); |
| + data |= (kBase64Decode[*input++] ); |
| + // And decode it to 3 (8-bit) bytes. |
| + decoded[decoded_count++] = (data >> 16) & 0xff; |
| + decoded[decoded_count++] = (data >> 8) & 0xff; |
| + decoded[decoded_count++] = (data ) & 0xff; |
| + |
| + // = is the base64 end marker. Remove decoded bytes if we see any. |
| + if (input[-1] == '=') decoded_count--; |
| + if (input[-2] == '=') decoded_count--; |
| + } |
| - g_context = ppb_g3d_interface->Create(g_instance, 0, attribs); |
| - int32_t success = ppb_instance_interface->BindGraphics(g_instance, g_context); |
| - if (success == PP_FALSE) { |
| - glSetCurrentContextPPAPI(0); |
| - printf("Failed to set context.\n"); |
| - return; |
| + int value = decoded[0]; |
| + int count = decoded[1]; |
| + decoded_count -= 2; |
| + // Move the other decoded bytes (if any) down. |
| + decoded[0] = decoded[2]; |
| + decoded[1] = decoded[3]; |
| + |
| + // Expand the RLE data. |
| + if (count == 0) |
| + count = 256; |
| + assert(output <= output_end); |
| + memset(output, value, count); |
| + output += count; |
| } |
| - glSetCurrentContextPPAPI(g_context); |
| - |
| - glViewport(0, 0, 640, 480); |
| - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| + assert(output == output_end); |
| } |
| -GLuint compileShader(GLenum type, const char* data) { |
| - const char* shaderStrings[1]; |
| - shaderStrings[0] = data; |
| - |
| +GLuint CompileShader(GLenum type, const char* data) { |
| GLuint shader = glCreateShader(type); |
| - glShaderSource(shader, 1, shaderStrings, NULL); |
| + glShaderSource(shader, 1, &data, NULL); |
| glCompileShader(shader); |
| + |
| + GLint compile_status; |
| + glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); |
| + if (compile_status != GL_TRUE) { |
| + // Shader failed to compile, let's see what the error is. |
| + char buffer[1024]; |
| + GLsizei length; |
| + glGetShaderInfoLog(shader, 1024, &length, &buffer[0]); |
|
noelallen1
2013/09/03 20:55:25
1024 vs sizeof(buffer)?
|
| + fprintf(stderr, "Shader failed to compile: %s\n", buffer); |
| + return 0; |
| + } |
| + |
| return shader; |
| } |
| -void InitProgram(void) { |
| - glSetCurrentContextPPAPI(g_context); |
| - |
| - g_vertexShader = compileShader(GL_VERTEX_SHADER, g_VShaderData); |
| - g_fragmentShader = compileShader(GL_FRAGMENT_SHADER, g_FShaderData); |
| +GLuint LinkProgram(GLuint frag_shader, GLuint vert_shader) { |
| + GLuint program = glCreateProgram(); |
| + glAttachShader(program, frag_shader); |
| + glAttachShader(program, vert_shader); |
| + glLinkProgram(program); |
| + |
| + GLint link_status; |
| + glGetProgramiv(program, GL_LINK_STATUS, &link_status); |
| + if (link_status != GL_TRUE) { |
| + // Program failed to link, let's see what the error is. |
| + char buffer[1024]; |
| + GLsizei length; |
| + glGetProgramInfoLog(program, 1024, &length, &buffer[0]); |
|
noelallen1
2013/09/03 20:55:25
same
|
| + fprintf(stderr, "Program failed to link: %s\n", buffer); |
| + return 0; |
| + } |
| - g_programObj = glCreateProgram(); |
| - glAttachShader(g_programObj, g_vertexShader); |
| - glAttachShader(g_programObj, g_fragmentShader); |
| - glLinkProgram(g_programObj); |
| + return program; |
| +} |
| - glGenBuffers(1, &g_vboID); |
| - glBindBuffer(GL_ARRAY_BUFFER, g_vboID); |
| - glBufferData(GL_ARRAY_BUFFER, |
| - 24 * sizeof(Vertex), |
| - (void*)&g_quadVertices[0], |
| - GL_STATIC_DRAW); |
| +const char kFragShaderSource[] = |
| + "precision mediump float;\n" |
| + "varying vec3 v_color;\n" |
| + "varying vec2 v_texcoord;\n" |
| + "uniform sampler2D u_texture;\n" |
| + "void main() {\n" |
| + " gl_FragColor = texture2D(u_texture, v_texcoord);\n" |
| + " gl_FragColor += vec4(v_color, 1);\n" |
| + "}\n"; |
| + |
| +const char kVertexShaderSource[] = |
| + "uniform mat4 u_mvp;\n" |
| + "attribute vec2 a_texcoord;\n" |
| + "attribute vec3 a_color;\n" |
| + "attribute vec4 a_position;\n" |
| + "varying vec3 v_color;\n" |
| + "varying vec2 v_texcoord;\n" |
| + "void main() {\n" |
| + " gl_Position = u_mvp * a_position;\n" |
| + " v_color = a_color;\n" |
| + " v_texcoord = a_texcoord;\n" |
| + "}\n"; |
| - 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); |
| +struct Vertex { |
| + float loc[3]; |
| + float color[3]; |
| + float tex[2]; |
| +}; |
| - // |
| - // 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); |
| +const Vertex kCubeVerts[24] = { |
| + // +Z (red arrow, black tip) |
| + {{-1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}}, |
| + {{+1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}}, |
| + {{+1.0, +1.0, +1.0}, {0.5, 0.0, 0.0}, {0.0, 1.0}}, |
| + {{-1.0, +1.0, +1.0}, {0.5, 0.0, 0.0}, {1.0, 1.0}}, |
| + |
| + // +X (green arrow, black tip) |
| + {{+1.0, -1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}}, |
| + {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}}, |
| + {{+1.0, +1.0, +1.0}, {0.0, 0.5, 0.0}, {0.0, 1.0}}, |
| + {{+1.0, -1.0, +1.0}, {0.0, 0.5, 0.0}, {1.0, 1.0}}, |
| + |
| + // +Y (blue arrow, black tip) |
| + {{-1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}}, |
| + {{-1.0, +1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}}, |
| + {{+1.0, +1.0, +1.0}, {0.0, 0.0, 0.5}, {0.0, 1.0}}, |
| + {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.5}, {1.0, 1.0}}, |
| + |
| + // -Z (red arrow, red tip) |
| + {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}}, |
| + {{-1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}}, |
| + {{-1.0, -1.0, -1.0}, {1.0, 0.0, 0.0}, {0.0, 0.0}}, |
| + {{+1.0, -1.0, -1.0}, {1.0, 0.0, 0.0}, {1.0, 0.0}}, |
| + |
| + // -X (green arrow, green tip) |
| + {{-1.0, +1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}}, |
| + {{-1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}}, |
| + {{-1.0, -1.0, -1.0}, {0.0, 1.0, 0.0}, {0.0, 0.0}}, |
| + {{-1.0, +1.0, -1.0}, {0.0, 1.0, 0.0}, {1.0, 0.0}}, |
| + |
| + // -Y (blue arrow, blue tip) |
| + {{+1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}}, |
| + {{+1.0, -1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}}, |
| + {{-1.0, -1.0, -1.0}, {0.0, 0.0, 1.0}, {0.0, 0.0}}, |
| + {{-1.0, -1.0, +1.0}, {0.0, 0.0, 1.0}, {1.0, 0.0}}, |
| +}; |
| - // |
| - // 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"); |
| -} |
| +const GLubyte kCubeIndexes[36] = { |
| + 2, 1, 0, 3, 2, 0, |
| + 6, 5, 4, 7, 6, 4, |
| + 10, 9, 8, 11, 10, 8, |
| + 14, 13, 12, 15, 14, 12, |
| + 18, 17, 16, 19, 18, 16, |
| + 22, 21, 20, 23, 22, 20, |
| +}; |
| -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; |
| +} // namespace |
| + |
| + |
| +class Graphics3DInstance : public pp::Instance { |
| + public: |
| + explicit Graphics3DInstance(PP_Instance instance) |
| + : pp::Instance(instance), |
| + callback_factory_(this), |
| + width_(0), |
| + height_(0), |
| + frag_shader_(0), |
| + vertex_shader_(0), |
| + program_(0), |
| + texture_loc_(0), |
| + position_loc_(0), |
| + color_loc_(0), |
| + mvp_loc_(0), |
| + x_angle_(0), |
| + y_angle_(0), |
| + animating_(true) {} |
| + |
| + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { |
| + return true; |
| } |
| -} |
| -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; |
| + virtual void DidChangeView(const pp::View& view) { |
| + int32_t new_width = view.GetRect().width(); |
| + int32_t new_height = view.GetRect().height(); |
| + |
| + if (context_.is_null()) { |
| + if (!InitGL(new_width, new_height)) { |
| + // failed. |
| + return; |
| + } |
| + |
| + InitShaders(); |
| + InitBuffers(); |
| + InitTexture(); |
| + MainLoop(0); |
| + } else { |
| + // Resize the buffers to the new size of the module. |
| + int32_t result = context_.ResizeBuffers(new_width, new_height); |
| + if (result < 0) { |
| + fprintf(stderr, |
| + "Unable to resize buffers to %d x %d!\n", |
| + new_width, |
| + new_height); |
| + return; |
| + } |
| } |
| - 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; |
| + width_ = new_width; |
| + height_ = new_height; |
| + glViewport(0, 0, width_, height_); |
| } |
| - return verts; |
| -} |
| - |
| -void Render(void) { |
| - static float xRot = 0.0; |
| - static float yRot = 0.0; |
| - |
| - xRot += 2.0f; |
| - yRot += 0.5f; |
| - if (xRot >= 360.0f) |
| - xRot = 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, 640.0f / 480.0f, 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); |
| -} |
| -typedef void (*OpenCB)(void* dataPtr); |
| -struct OpenRequest { |
| - PP_Resource loader_; |
| - PP_Resource request_; |
| - char* buf_; |
| - void* data_; |
| - int64_t size_; |
| - int64_t avail_; |
| - OpenCB cb_; |
| -}; |
| + virtual void HandleMessage(const pp::Var& message) { |
| + // A bool message sets whether the cube is animating or not. |
| + if (message.is_bool()) { |
| + animating_ = message.AsBool(); |
| + return; |
| + } |
| -void FreeRequest(OpenRequest* req) { |
| - if (req) { |
| - ppb_core_interface->ReleaseResource(req->request_); |
| - ppb_core_interface->ReleaseResource(req->loader_); |
| - free(req); |
| - } |
| -} |
| + // An array message sets the current x and y rotation. |
| + if (!message.is_array()) { |
| + fprintf(stderr, "Expected array message.\n"); |
| + return; |
| + } |
| -static void URLPartialRead(void* user_data, int mode) { |
| - OpenRequest* req = (OpenRequest*)user_data; |
| - int64_t total; |
| - int32_t cnt; |
| + pp::VarArray array(message); |
| + if (array.GetLength() != 2) { |
| + fprintf(stderr, "Expected array of length 2.\n"); |
| + return; |
| + } |
| - if (mode < 0) { |
| - free(req->buf_); |
| - req->cb_(NULL); |
| - FreeRequest(req); |
| - return; |
| - } |
| + pp::Var x_angle_var = array.Get(0); |
| + if (x_angle_var.is_int()) { |
| + x_angle_ = x_angle_var.AsInt(); |
| + } else if (x_angle_var.is_double()) { |
| + x_angle_ = x_angle_var.AsDouble(); |
| + } else { |
| + fprintf(stderr, "Expected value to be an int or double.\n"); |
| + } |
| - req->avail_ += mode; |
| - total = req->size_ - req->avail_; |
| - |
| - cnt = (total > LONG_MAX) ? LONG_MAX : (int32_t) total; |
| - // If we still have more to do, re-issue the read. |
| - if (cnt > 0) { |
| - int32_t bytes = ppb_urlloader_interface->ReadResponseBody( |
| - req->loader_, |
| - (void*)&req->buf_[req->avail_], |
| - cnt, |
| - PP_MakeCompletionCallback(URLPartialRead, req)); |
| - |
| - // If the reissue completes immediately, then process it. |
| - if (bytes != PP_OK_COMPLETIONPENDING) { |
| - URLPartialRead(user_data, bytes); |
| + pp::Var y_angle_var = array.Get(1); |
| + if (y_angle_var.is_int()) { |
| + y_angle_ = y_angle_var.AsInt(); |
| + } else if (y_angle_var.is_double()) { |
| + y_angle_ = y_angle_var.AsDouble(); |
| + } else { |
| + fprintf(stderr, "Expected value to be an int or double.\n"); |
| } |
| - return; |
| } |
| - // Nothing left, so signal complete. |
| - req->cb_(req); |
| - FreeRequest(req); |
| - printf("Loaded\n"); |
| -} |
| + private: |
| + bool InitGL(int32_t new_width, int32_t new_height) { |
| + if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) { |
| + fprintf(stderr, "Unable to initialize GL PPAPI!\n"); |
| + return false; |
| + } |
| -static void URLOpened(void* user_data, int mode) { |
| - OpenRequest* req = (OpenRequest*)user_data; |
| + const int32_t attrib_list[] = { |
| + PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, |
| + PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24, |
| + PP_GRAPHICS3DATTRIB_WIDTH, new_width, |
| + PP_GRAPHICS3DATTRIB_HEIGHT, new_height, |
| + PP_GRAPHICS3DATTRIB_NONE |
| + }; |
| - int64_t cur, total; |
| - int32_t cnt; |
| - ppb_urlloader_interface->GetDownloadProgress(req->loader_, &cur, &total); |
| + context_ = pp::Graphics3D(this, attrib_list); |
| + if (!BindGraphics(context_)) { |
| + fprintf(stderr, "Unable to bind 3d context!\n"); |
| + context_ = pp::Graphics3D(); |
| + glSetCurrentContextPPAPI(0); |
| + return false; |
| + } |
| - // If we can't preallocate the buffer because the size is unknown, then |
| - // fail the load. |
| - if (total == -1) { |
| - req->cb_(NULL); |
| - FreeRequest(req); |
| - return; |
| + glSetCurrentContextPPAPI(context_.pp_resource()); |
| + return true; |
| } |
| - // Otherwise allocate a buffer with enough space for a terminating |
| - // NULL in case we need one. |
| - cnt = (total > LONG_MAX) ? LONG_MAX : (int32_t) total; |
| - req->buf_ = (char*)malloc(cnt + 1); |
| - req->buf_[cnt] = 0; |
| - req->size_ = cnt; |
| - int32_t bytes = ppb_urlloader_interface->ReadResponseBody( |
| - req->loader_, |
| - req->buf_, |
| - cnt, |
| - PP_MakeCompletionCallback(URLPartialRead, req)); |
| - |
| - // Usually we are pending. |
| - if (bytes == PP_OK_COMPLETIONPENDING) |
| - return; |
| - |
| - // But if we did complete the read, then dispatch the handler. |
| - URLPartialRead(req, bytes); |
| -} |
| + void InitShaders() { |
| + frag_shader_ = CompileShader(GL_FRAGMENT_SHADER, kFragShaderSource); |
| + if (!frag_shader_) |
| + return; |
| -void LoadURL(PP_Instance inst, const char* url, OpenCB cb, void* data) { |
| - OpenRequest* req = (OpenRequest*)malloc(sizeof(OpenRequest)); |
| - memset(req, 0, sizeof(OpenRequest)); |
| + vertex_shader_ = CompileShader(GL_VERTEX_SHADER, kVertexShaderSource); |
| + if (!vertex_shader_) |
| + return; |
| - req->loader_ = ppb_urlloader_interface->Create(inst); |
| - req->request_ = ppb_urlrequestinfo_interface->Create(inst); |
| - req->cb_ = cb; |
| - req->data_ = data; |
| + program_ = LinkProgram(frag_shader_, vertex_shader_); |
| + if (!program_) |
| + return; |
| - if (!req->loader_ || !req->request_) { |
| - cb(NULL); |
| - FreeRequest(req); |
| - return; |
| + texture_loc_ = glGetUniformLocation(program_, "u_texture"); |
| + position_loc_ = glGetAttribLocation(program_, "a_position"); |
| + texcoord_loc_ = glGetAttribLocation(program_, "a_texcoord"); |
| + color_loc_ = glGetAttribLocation(program_, "a_color"); |
| + mvp_loc_ = glGetUniformLocation(program_, "u_mvp"); |
| } |
| - ppb_urlrequestinfo_interface->SetProperty( |
| - req->request_, PP_URLREQUESTPROPERTY_URL, CStrToVar(url)); |
| - ppb_urlrequestinfo_interface->SetProperty( |
| - req->request_, PP_URLREQUESTPROPERTY_METHOD, CStrToVar("GET")); |
| - ppb_urlrequestinfo_interface->SetProperty( |
| - req->request_, |
| - PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS, |
| - PP_MakeBool(PP_TRUE)); |
| - |
| - int val = ppb_urlloader_interface->Open( |
| - req->loader_, req->request_, PP_MakeCompletionCallback(URLOpened, req)); |
| - |
| - if (val != PP_OK_COMPLETIONPENDING) { |
| - cb(NULL); |
| - free(req); |
| + void InitBuffers() { |
| + glGenBuffers(1, &vertex_buffer_); |
| + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_); |
| + glBufferData(GL_ARRAY_BUFFER, sizeof(kCubeVerts), &kCubeVerts[0], |
| + GL_STATIC_DRAW); |
| + |
| + glGenBuffers(1, &index_buffer_); |
| + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_); |
| + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kCubeIndexes), |
| + &kCubeIndexes[0], GL_STATIC_DRAW); |
| } |
| -} |
| -void Loaded(void* data) { |
| - OpenRequest* req = (OpenRequest*)data; |
| - if (req && req->buf_) { |
| - char** pptr = (char**)req->data_; |
| - *pptr = req->buf_; |
| - g_LoadCnt++; |
| - return; |
| + void InitTexture() { |
| + DecompressTexture(); |
| + glGenTextures(1, &texture_); |
| + glBindTexture(GL_TEXTURE_2D, texture_); |
| + 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_texture_data[0]); |
| } |
| - PostMessage("Failed to load asset.\n"); |
| -} |
| -/** |
| - * Called when the NaCl module is instantiated on the web page. The identifier |
| - * of the new instance will be passed in as the first argument (this value is |
| - * generated by the browser and is an opaque handle). This is called for each |
| - * instantiation of the NaCl module, which is each time the <embed> tag for |
| - * this module is encountered. |
| - * |
| - * If this function reports a failure (by returning @a PP_FALSE), the NaCl |
| - * module will be deleted and DidDestroy will be called. |
| - * @param[in] instance The identifier of the new instance representing this |
| - * NaCl module. |
| - * @param[in] argc The number of arguments contained in @a argn and @a argv. |
| - * @param[in] argn An array of argument names. These argument names are |
| - * supplied in the <embed> tag, for example: |
| - * <embed id="nacl_module" dimensions="2"> |
| - * will produce two arguments, one named "id" and one named "dimensions". |
| - * @param[in] argv An array of argument values. These are the values of the |
| - * arguments listed in the <embed> tag. In the above example, there will |
| - * be two elements in this array, "nacl_module" and "2". The indices of |
| - * these values match the indices of the corresponding names in @a argn. |
| - * @return @a PP_TRUE on success. |
| - */ |
| -static PP_Bool Instance_DidCreate(PP_Instance instance, |
| - uint32_t argc, |
| - const char* argn[], |
| - const char* argv[]) { |
| - g_instance = instance; |
| - LoadURL(instance, "hello.raw", Loaded, &g_TextureData); |
| - LoadURL(instance, "vertex_shader_es2.vert", Loaded, &g_VShaderData); |
| - LoadURL(instance, "fragment_shader_es2.frag", Loaded, &g_FShaderData); |
| - g_quadVertices = BuildCube(); |
| - return PP_TRUE; |
| -} |
| + void Animate() { |
| + if (animating_) { |
| + x_angle_ = fmod(360.0f + x_angle_ + kXAngleDelta, 360.0f); |
| + y_angle_ = fmod(360.0f + y_angle_ + kYAngleDelta, 360.0f); |
| + |
| + // Send new values to JavaScript. |
| + pp::VarArray array; |
| + array.SetLength(2); |
| + array.Set(0, x_angle_); |
| + array.Set(1, y_angle_); |
| + PostMessage(array); |
| + } |
| + } |
| -/** |
| - * Called when the NaCl module is destroyed. This will always be called, |
| - * even if DidCreate returned failure. This routine should deallocate any data |
| - * associated with the instance. |
| - * @param[in] instance The identifier of the instance representing this NaCl |
| - * module. |
| - */ |
| -static void Instance_DidDestroy(PP_Instance instance) { |
| - delete[] g_TextureData; |
| - delete[] g_VShaderData; |
| - delete[] g_FShaderData; |
| - delete[] g_quadVertices; |
| -} |
| + void Render() { |
| + glClearColor(0.5, 0.5, 0.5, 1); |
| + glClearDepthf(1.0f); |
| + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| + glEnable(GL_DEPTH_TEST); |
| + |
| + //set what program to use |
| + glUseProgram(program_); |
| + glActiveTexture(GL_TEXTURE0); |
| + glBindTexture(GL_TEXTURE_2D, texture_); |
| + glUniform1i(texture_loc_, 0); |
| + |
| + //create our perspective matrix |
| + float mvp[16]; |
| + float trs[16]; |
| + float rot[16]; |
| + |
| + identity_matrix(mvp); |
| + const float aspect_ratio = static_cast<float>(width_) / height_; |
| + glhPerspectivef2(&mvp[0], kFovY, aspect_ratio, kZNear, kZFar); |
| + |
| + translate_matrix(0, 0, kCameraZ, trs); |
| + rotate_matrix(x_angle_, y_angle_, 0.0f, rot); |
| + multiply_matrix(trs, rot, trs); |
| + multiply_matrix(mvp, trs, mvp); |
| + glUniformMatrix4fv(mvp_loc_, 1, GL_FALSE, mvp); |
| + |
| + //define the attributes of the vertex |
| + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_); |
| + glVertexAttribPointer(position_loc_, |
| + 3, |
| + GL_FLOAT, |
| + GL_FALSE, |
| + sizeof(Vertex), |
| + reinterpret_cast<void*>(offsetof(Vertex, loc))); |
| + glEnableVertexAttribArray(position_loc_); |
| + glVertexAttribPointer(color_loc_, |
| + 3, |
| + GL_FLOAT, |
| + GL_FALSE, |
| + sizeof(Vertex), |
| + reinterpret_cast<void*>(offsetof(Vertex, color))); |
| + glEnableVertexAttribArray(color_loc_); |
| + glVertexAttribPointer(texcoord_loc_, |
| + 2, |
| + GL_FLOAT, |
| + GL_FALSE, |
| + sizeof(Vertex), |
| + reinterpret_cast<void*>(offsetof(Vertex, tex))); |
| + glEnableVertexAttribArray(texcoord_loc_); |
| + |
| + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_); |
| + glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, 0); |
| + } |
| -/** |
| - * Called when the position, the size, or the clip rect of the element in the |
| - * browser that corresponds to this NaCl module has changed. |
| - * @param[in] instance The identifier of the instance representing this NaCl |
| - * module. |
| - * @param[in] position The location on the page of this NaCl module. This is |
| - * relative to the top left corner of the viewport, which changes as the |
| - * page is scrolled. |
| - * @param[in] clip The visible region of the NaCl module. This is relative to |
| - * the top left of the plugin's coordinate system (not the page). If the |
| - * plugin is invisible, @a clip will be (0, 0, 0, 0). |
| - */ |
| -static void Instance_DidChangeView(PP_Instance instance, |
| - PP_Resource view_resource) { |
| - if (g_context == 0) { |
| - InitGL(); |
| - MainLoop(NULL, 0); |
| + void MainLoop(int32_t) { |
| + Animate(); |
| + Render(); |
| + context_.SwapBuffers( |
| + callback_factory_.NewCallback(&Graphics3DInstance::MainLoop)); |
| } |
| -} |
| -/** |
| - * Notification that the given NaCl module has gained or lost focus. |
| - * Having focus means that keyboard events will be sent to the NaCl module |
| - * represented by @a instance. A NaCl module's default condition is that it |
| - * will not have focus. |
| - * |
| - * Note: clicks on NaCl modules will give focus only if you handle the |
| - * click event. You signal if you handled it by returning @a true from |
| - * HandleInputEvent. Otherwise the browser will bubble the event and give |
| - * focus to the element on the page that actually did end up consuming it. |
| - * If you're not getting focus, check to make sure you're returning true from |
| - * the mouse click in HandleInputEvent. |
| - * @param[in] instance The identifier of the instance representing this NaCl |
| - * module. |
| - * @param[in] has_focus Indicates whether this NaCl module gained or lost |
| - * event focus. |
| - */ |
| -static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {} |
| - |
| -/** |
| - * Handler that gets called after a full-frame module is instantiated based on |
| - * registered MIME types. This function is not called on NaCl modules. This |
| - * function is essentially a place-holder for the required function pointer in |
| - * the PPP_Instance structure. |
| - * @param[in] instance The identifier of the instance representing this NaCl |
| - * module. |
| - * @param[in] url_loader A PP_Resource an open PPB_URLLoader instance. |
| - * @return PP_FALSE. |
| - */ |
| -static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, |
| - PP_Resource url_loader) { |
| - /* NaCl modules do not need to handle the document load function. */ |
| - return PP_FALSE; |
| -} |
| + pp::CompletionCallbackFactory<Graphics3DInstance> callback_factory_; |
| + pp::Graphics3D context_; |
| + int32_t width_; |
| + int32_t height_; |
| + GLuint frag_shader_; |
| + GLuint vertex_shader_; |
| + GLuint program_; |
| + GLuint vertex_buffer_; |
| + GLuint index_buffer_; |
| + GLuint texture_; |
| + |
| + GLuint texture_loc_; |
| + GLuint position_loc_; |
| + GLuint texcoord_loc_; |
| + GLuint color_loc_; |
| + GLuint mvp_loc_; |
| + |
| + float x_angle_; |
| + float y_angle_; |
| + bool animating_; |
| +}; |
| -/** |
| - * Entry points for the module. |
| - * Initialize needed interfaces: PPB_Core, PPB_Messaging and PPB_Var. |
| - * @param[in] a_module_id module ID |
| - * @param[in] get_browser pointer to PPB_GetInterface |
| - * @return PP_OK on success, any other value on failure. |
| - */ |
| -PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, |
| - PPB_GetInterface get_browser) { |
| - ppb_core_interface = (PPB_Core*)(get_browser(PPB_CORE_INTERFACE)); |
| - ppb_instance_interface = (PPB_Instance*)get_browser(PPB_INSTANCE_INTERFACE); |
| - ppb_messaging_interface = |
| - (PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE)); |
| - ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE)); |
| - ppb_urlloader_interface = |
| - (PPB_URLLoader*)(get_browser(PPB_URLLOADER_INTERFACE)); |
| - ppb_urlrequestinfo_interface = |
| - (PPB_URLRequestInfo*)(get_browser(PPB_URLREQUESTINFO_INTERFACE)); |
| - ppb_g3d_interface = (PPB_Graphics3D*)get_browser(PPB_GRAPHICS_3D_INTERFACE); |
| - if (!glInitializePPAPI(get_browser)) |
| - return PP_ERROR_FAILED; |
| - return PP_OK; |
| -} |
| +class Graphics3DModule : public pp::Module { |
| + public: |
| + Graphics3DModule() : pp::Module() {} |
| + virtual ~Graphics3DModule() {} |
| -/** |
| - * Returns an interface pointer for the interface of the given name, or NULL |
| - * if the interface is not supported. |
| - * @param[in] interface_name name of the interface |
| - * @return pointer to the interface |
| - */ |
| -PP_EXPORT const void* PPP_GetInterface(const char* interface_name) { |
| - if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { |
| - static PPP_Instance instance_interface = { |
| - &Instance_DidCreate, |
| - &Instance_DidDestroy, |
| - &Instance_DidChangeView, |
| - &Instance_DidChangeFocus, |
| - &Instance_HandleDocumentLoad, |
| - }; |
| - return &instance_interface; |
| + virtual pp::Instance* CreateInstance(PP_Instance instance) { |
| + return new Graphics3DInstance(instance); |
| } |
| - return NULL; |
| -} |
| +}; |
| -/** |
| - * Called before the plugin module is unloaded. |
| - */ |
| -PP_EXPORT void PPP_ShutdownModule() {} |
| +namespace pp { |
| +Module* CreateModule() { return new Graphics3DModule(); } |
| +} // namespace pp |