Home | History | Annotate | Download | only in graphics_3d
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 //-----------------------------------------------------------------------------
      6 // The spinning Cube
      7 //-----------------------------------------------------------------------------
      8 
      9 #define _USE_MATH_DEFINES 1
     10 #include <limits.h>
     11 #include <math.h>
     12 #include <stdarg.h>
     13 #include <stddef.h>
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 
     18 #include "ppapi/c/pp_completion_callback.h"
     19 #include "ppapi/c/pp_errors.h"
     20 #include "ppapi/c/pp_graphics_3d.h"
     21 #include "ppapi/c/pp_module.h"
     22 #include "ppapi/c/pp_stdint.h"
     23 #include "ppapi/c/pp_var.h"
     24 #include "ppapi/c/ppb.h"
     25 #include "ppapi/c/ppb_core.h"
     26 #include "ppapi/c/ppb_graphics_3d.h"
     27 #include "ppapi/c/ppb_instance.h"
     28 #include "ppapi/c/ppb_messaging.h"
     29 #include "ppapi/c/ppb_opengles2.h"
     30 #include "ppapi/c/ppb_url_loader.h"
     31 #include "ppapi/c/ppb_url_request_info.h"
     32 #include "ppapi/c/ppb_var.h"
     33 #include "ppapi/c/ppp.h"
     34 #include "ppapi/c/ppp_instance.h"
     35 #include "ppapi/c/ppp_messaging.h"
     36 
     37 #include "ppapi/c/ppp_graphics_3d.h"
     38 #include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
     39 
     40 #include <GLES2/gl2.h>
     41 #include "matrix.h"
     42 
     43 static PPB_Messaging* ppb_messaging_interface = NULL;
     44 static PPB_Var* ppb_var_interface = NULL;
     45 static PPB_Core* ppb_core_interface = NULL;
     46 static PPB_Graphics3D* ppb_g3d_interface = NULL;
     47 static PPB_Instance* ppb_instance_interface = NULL;
     48 static PPB_URLRequestInfo* ppb_urlrequestinfo_interface = NULL;
     49 static PPB_URLLoader* ppb_urlloader_interface = NULL;
     50 
     51 static PP_Instance g_instance;
     52 static PP_Resource g_context;
     53 
     54 GLuint g_positionLoc;
     55 GLuint g_texCoordLoc;
     56 GLuint g_colorLoc;
     57 GLuint g_MVPLoc;
     58 GLuint g_vboID;
     59 GLuint g_ibID;
     60 GLubyte g_Indices[36];
     61 
     62 GLuint g_programObj;
     63 GLuint g_vertexShader;
     64 GLuint g_fragmentShader;
     65 
     66 GLuint g_textureLoc = 0;
     67 GLuint g_textureID = 0;
     68 
     69 float g_fSpinX = 0.0f;
     70 float g_fSpinY = 0.0f;
     71 
     72 //-----------------------------------------------------------------------------
     73 // Rendering Assets
     74 //-----------------------------------------------------------------------------
     75 struct Vertex {
     76   float tu, tv;
     77   float color[3];
     78   float loc[3];
     79 };
     80 
     81 Vertex* g_quadVertices = NULL;
     82 const char* g_TextureData = NULL;
     83 const char* g_VShaderData = NULL;
     84 const char* g_FShaderData = NULL;
     85 int g_LoadCnt = 0;
     86 
     87 //-----------------------------------------------------------------------------
     88 // PROTOTYPES
     89 //-----------------------------------------------------------------------------
     90 void PostMessage(const char* fmt, ...);
     91 char* LoadFile(const char* fileName);
     92 
     93 void BuildQuad(Vertex* verts, int axis[3], float depth, float color[3]);
     94 Vertex* BuildCube(void);
     95 
     96 void InitGL(void);
     97 void InitProgram(void);
     98 void Render(void);
     99 
    100 static struct PP_Var CStrToVar(const char* str) {
    101   if (ppb_var_interface != NULL) {
    102     return ppb_var_interface->VarFromUtf8(str, strlen(str));
    103   }
    104   return PP_MakeUndefined();
    105 }
    106 
    107 void PostMessage(const char* fmt, ...) {
    108   va_list args;
    109   va_start(args, fmt);
    110 
    111   char msg[4096];
    112   vsnprintf(msg, sizeof(msg), fmt, args);
    113 
    114   if (ppb_messaging_interface)
    115     ppb_messaging_interface->PostMessage(g_instance, CStrToVar(msg));
    116 
    117   va_end(args);
    118 }
    119 
    120 void MainLoop(void* foo, int bar) {
    121   if (g_LoadCnt == 3) {
    122     InitProgram();
    123     g_LoadCnt++;
    124   }
    125   if (g_LoadCnt > 3) {
    126     Render();
    127     PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0);
    128     ppb_g3d_interface->SwapBuffers(g_context, cc);
    129   } else {
    130     PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0);
    131     ppb_core_interface->CallOnMainThread(0, cc, 0);
    132   }
    133 }
    134 
    135 void InitGL(void) {
    136   int32_t attribs[] = {
    137     PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
    138     PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
    139     PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8,
    140     PP_GRAPHICS3DATTRIB_SAMPLES, 0,
    141     PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
    142     PP_GRAPHICS3DATTRIB_WIDTH, 640,
    143     PP_GRAPHICS3DATTRIB_HEIGHT, 480,
    144     PP_GRAPHICS3DATTRIB_NONE
    145   };
    146 
    147   g_context = ppb_g3d_interface->Create(g_instance, 0, attribs);
    148   int32_t success = ppb_instance_interface->BindGraphics(g_instance, g_context);
    149   if (success == PP_FALSE) {
    150     glSetCurrentContextPPAPI(0);
    151     printf("Failed to set context.\n");
    152     return;
    153   }
    154   glSetCurrentContextPPAPI(g_context);
    155 
    156   glViewport(0, 0, 640, 480);
    157   glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    158 }
    159 
    160 GLuint compileShader(GLenum type, const char* data) {
    161   const char* shaderStrings[1];
    162   shaderStrings[0] = data;
    163 
    164   GLuint shader = glCreateShader(type);
    165   glShaderSource(shader, 1, shaderStrings, NULL);
    166   glCompileShader(shader);
    167   return shader;
    168 }
    169 
    170 void InitProgram(void) {
    171   glSetCurrentContextPPAPI(g_context);
    172 
    173   g_vertexShader = compileShader(GL_VERTEX_SHADER, g_VShaderData);
    174   g_fragmentShader = compileShader(GL_FRAGMENT_SHADER, g_FShaderData);
    175 
    176   g_programObj = glCreateProgram();
    177   glAttachShader(g_programObj, g_vertexShader);
    178   glAttachShader(g_programObj, g_fragmentShader);
    179   glLinkProgram(g_programObj);
    180 
    181   glGenBuffers(1, &g_vboID);
    182   glBindBuffer(GL_ARRAY_BUFFER, g_vboID);
    183   glBufferData(GL_ARRAY_BUFFER,
    184                24 * sizeof(Vertex),
    185                (void*)&g_quadVertices[0],
    186                GL_STATIC_DRAW);
    187 
    188   glGenBuffers(1, &g_ibID);
    189   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ibID);
    190   glBufferData(GL_ELEMENT_ARRAY_BUFFER,
    191                36 * sizeof(char),
    192                (void*)&g_Indices[0],
    193                GL_STATIC_DRAW);
    194 
    195   //
    196   // Create a texture to test out our fragment shader...
    197   //
    198   glGenTextures(1, &g_textureID);
    199   glBindTexture(GL_TEXTURE_2D, g_textureID);
    200   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    201   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    202   glTexImage2D(GL_TEXTURE_2D,
    203                0,
    204                GL_RGB,
    205                128,
    206                128,
    207                0,
    208                GL_RGB,
    209                GL_UNSIGNED_BYTE,
    210                g_TextureData);
    211 
    212   //
    213   // Locate some parameters by name so we can set them later...
    214   //
    215   g_textureLoc = glGetUniformLocation(g_programObj, "arrowTexture");
    216   g_positionLoc = glGetAttribLocation(g_programObj, "a_position");
    217   g_texCoordLoc = glGetAttribLocation(g_programObj, "a_texCoord");
    218   g_colorLoc = glGetAttribLocation(g_programObj, "a_color");
    219   g_MVPLoc = glGetUniformLocation(g_programObj, "a_MVP");
    220 }
    221 
    222 void BuildQuad(Vertex* verts, int axis[3], float depth, float color[3]) {
    223   static float X[4] = { -1.0f, 1.0f, 1.0f, -1.0f };
    224   static float Y[4] = { -1.0f, -1.0f, 1.0f, 1.0f };
    225 
    226   for (int i = 0; i < 4; i++) {
    227     verts[i].tu = (1.0 - X[i]) / 2.0f;
    228     verts[i].tv = (Y[i] + 1.0f) / -2.0f * depth;
    229     verts[i].loc[axis[0]] = X[i] * depth;
    230     verts[i].loc[axis[1]] = Y[i] * depth;
    231     verts[i].loc[axis[2]] = depth;
    232     for (int j = 0; j < 3; j++)
    233       verts[i].color[j] = color[j] * (Y[i] + 1.0f) / 2.0f;
    234   }
    235 }
    236 
    237 Vertex* BuildCube() {
    238   Vertex* verts = new Vertex[24];
    239   for (int i = 0; i < 3; i++) {
    240     int Faxis[3];
    241     int Baxis[3];
    242     float Fcolor[3];
    243     float Bcolor[3];
    244     for (int j = 0; j < 3; j++) {
    245       Faxis[j] = (j + i) % 3;
    246       Baxis[j] = (j + i) % 3;
    247     }
    248     memset(Fcolor, 0, sizeof(float) * 3);
    249     memset(Bcolor, 0, sizeof(float) * 3);
    250     Fcolor[i] = 0.5f;
    251     Bcolor[i] = 1.0f;
    252     BuildQuad(&verts[0 + i * 4], Faxis, 1.0f, Fcolor);
    253     BuildQuad(&verts[12 + i * 4], Baxis, -1.0f, Bcolor);
    254   }
    255 
    256   for (int i = 0; i < 6; i++) {
    257     g_Indices[i * 6 + 0] = 2 + i * 4;
    258     g_Indices[i * 6 + 1] = 1 + i * 4;
    259     g_Indices[i * 6 + 2] = 0 + i * 4;
    260     g_Indices[i * 6 + 3] = 3 + i * 4;
    261     g_Indices[i * 6 + 4] = 2 + i * 4;
    262     g_Indices[i * 6 + 5] = 0 + i * 4;
    263   }
    264   return verts;
    265 }
    266 
    267 void Render(void) {
    268   static float xRot = 0.0;
    269   static float yRot = 0.0;
    270 
    271   xRot += 2.0f;
    272   yRot += 0.5f;
    273   if (xRot >= 360.0f)
    274     xRot = 0.0;
    275   if (yRot >= 360.0f)
    276     yRot = 0.0;
    277 
    278   glClearColor(0.5, 0.5, 0.5, 1);
    279   glClearDepthf(1.0);
    280   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    281   glEnable(GL_DEPTH_TEST);
    282 
    283   //set what program to use
    284   glUseProgram(g_programObj);
    285   glActiveTexture(GL_TEXTURE0);
    286   glBindTexture(GL_TEXTURE_2D, g_textureID);
    287   glUniform1i(g_textureLoc, 0);
    288 
    289   //create our perspective matrix
    290   float mpv[16];
    291   float trs[16];
    292   float rot[16];
    293 
    294   identity_matrix(mpv);
    295   glhPerspectivef2(&mpv[0], 45.0f, 640.0f / 480.0f, 1, 10);
    296 
    297   translate_matrix(0, 0, -4.0, trs);
    298   rotate_matrix(xRot, yRot, 0.0f, rot);
    299   multiply_matrix(trs, rot, trs);
    300   multiply_matrix(mpv, trs, mpv);
    301   glUniformMatrix4fv(g_MVPLoc, 1, GL_FALSE, (GLfloat*)mpv);
    302 
    303   //define the attributes of the vertex
    304   glBindBuffer(GL_ARRAY_BUFFER, g_vboID);
    305   glVertexAttribPointer(g_positionLoc,
    306                         3,
    307                         GL_FLOAT,
    308                         GL_FALSE,
    309                         sizeof(Vertex),
    310                         (void*)offsetof(Vertex, loc));
    311   glEnableVertexAttribArray(g_positionLoc);
    312   glVertexAttribPointer(g_texCoordLoc,
    313                         2,
    314                         GL_FLOAT,
    315                         GL_FALSE,
    316                         sizeof(Vertex),
    317                         (void*)offsetof(Vertex, tu));
    318   glEnableVertexAttribArray(g_texCoordLoc);
    319   glVertexAttribPointer(g_colorLoc,
    320                         3,
    321                         GL_FLOAT,
    322                         GL_FALSE,
    323                         sizeof(Vertex),
    324                         (void*)offsetof(Vertex, color));
    325   glEnableVertexAttribArray(g_colorLoc);
    326 
    327   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ibID);
    328   glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, 0);
    329 }
    330 
    331 typedef void (*OpenCB)(void* dataPtr);
    332 struct OpenRequest {
    333   PP_Resource loader_;
    334   PP_Resource request_;
    335   char* buf_;
    336   void* data_;
    337   int64_t size_;
    338   int64_t avail_;
    339   OpenCB cb_;
    340 };
    341 
    342 void FreeRequest(OpenRequest* req) {
    343   if (req) {
    344     ppb_core_interface->ReleaseResource(req->request_);
    345     ppb_core_interface->ReleaseResource(req->loader_);
    346     free(req);
    347   }
    348 }
    349 
    350 static void URLPartialRead(void* user_data, int mode) {
    351   OpenRequest* req = (OpenRequest*)user_data;
    352   int64_t total;
    353   int32_t cnt;
    354 
    355   if (mode < 0) {
    356     free(req->buf_);
    357     req->cb_(NULL);
    358     FreeRequest(req);
    359     return;
    360   }
    361 
    362   req->avail_ += mode;
    363   total = req->size_ - req->avail_;
    364 
    365   cnt = (total > LONG_MAX) ? LONG_MAX : (int32_t) total;
    366   // If we still have more to do, re-issue the read.
    367   if (cnt > 0) {
    368     int32_t bytes = ppb_urlloader_interface->ReadResponseBody(
    369         req->loader_,
    370         (void*)&req->buf_[req->avail_],
    371         cnt,
    372         PP_MakeCompletionCallback(URLPartialRead, req));
    373 
    374     // If the reissue completes immediately, then process it.
    375     if (bytes != PP_OK_COMPLETIONPENDING) {
    376       URLPartialRead(user_data, bytes);
    377     }
    378     return;
    379   }
    380 
    381   // Nothing left, so signal complete.
    382   req->cb_(req);
    383   FreeRequest(req);
    384   printf("Loaded\n");
    385 }
    386 
    387 static void URLOpened(void* user_data, int mode) {
    388   OpenRequest* req = (OpenRequest*)user_data;
    389 
    390   int64_t cur, total;
    391   int32_t cnt;
    392   ppb_urlloader_interface->GetDownloadProgress(req->loader_, &cur, &total);
    393 
    394   // If we can't preallocate the buffer because the size is unknown, then
    395   // fail the load.
    396   if (total == -1) {
    397     req->cb_(NULL);
    398     FreeRequest(req);
    399     return;
    400   }
    401 
    402   // Otherwise allocate a buffer with enough space for a terminating
    403   // NULL in case we need one.
    404   cnt = (total > LONG_MAX) ? LONG_MAX : (int32_t) total;
    405   req->buf_ = (char*)malloc(cnt + 1);
    406   req->buf_[cnt] = 0;
    407   req->size_ = cnt;
    408   int32_t bytes = ppb_urlloader_interface->ReadResponseBody(
    409       req->loader_,
    410       req->buf_,
    411       cnt,
    412       PP_MakeCompletionCallback(URLPartialRead, req));
    413 
    414   // Usually we are pending.
    415   if (bytes == PP_OK_COMPLETIONPENDING)
    416     return;
    417 
    418   // But if we did complete the read, then dispatch the handler.
    419   URLPartialRead(req, bytes);
    420 }
    421 
    422 void LoadURL(PP_Instance inst, const char* url, OpenCB cb, void* data) {
    423   OpenRequest* req = (OpenRequest*)malloc(sizeof(OpenRequest));
    424   memset(req, 0, sizeof(OpenRequest));
    425 
    426   req->loader_ = ppb_urlloader_interface->Create(inst);
    427   req->request_ = ppb_urlrequestinfo_interface->Create(inst);
    428   req->cb_ = cb;
    429   req->data_ = data;
    430 
    431   if (!req->loader_ || !req->request_) {
    432     cb(NULL);
    433     FreeRequest(req);
    434     return;
    435   }
    436 
    437   ppb_urlrequestinfo_interface->SetProperty(
    438       req->request_, PP_URLREQUESTPROPERTY_URL, CStrToVar(url));
    439   ppb_urlrequestinfo_interface->SetProperty(
    440       req->request_, PP_URLREQUESTPROPERTY_METHOD, CStrToVar("GET"));
    441   ppb_urlrequestinfo_interface->SetProperty(
    442       req->request_,
    443       PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS,
    444       PP_MakeBool(PP_TRUE));
    445 
    446   int val = ppb_urlloader_interface->Open(
    447       req->loader_, req->request_, PP_MakeCompletionCallback(URLOpened, req));
    448 
    449   if (val != PP_OK_COMPLETIONPENDING) {
    450     cb(NULL);
    451     free(req);
    452   }
    453 }
    454 
    455 void Loaded(void* data) {
    456   OpenRequest* req = (OpenRequest*)data;
    457   if (req && req->buf_) {
    458     char** pptr = (char**)req->data_;
    459     *pptr = req->buf_;
    460     g_LoadCnt++;
    461     return;
    462   }
    463   PostMessage("Failed to load asset.\n");
    464 }
    465 
    466 /**
    467  * Called when the NaCl module is instantiated on the web page. The identifier
    468  * of the new instance will be passed in as the first argument (this value is
    469  * generated by the browser and is an opaque handle).  This is called for each
    470  * instantiation of the NaCl module, which is each time the <embed> tag for
    471  * this module is encountered.
    472  *
    473  * If this function reports a failure (by returning @a PP_FALSE), the NaCl
    474  * module will be deleted and DidDestroy will be called.
    475  * @param[in] instance The identifier of the new instance representing this
    476  *     NaCl module.
    477  * @param[in] argc The number of arguments contained in @a argn and @a argv.
    478  * @param[in] argn An array of argument names.  These argument names are
    479  *     supplied in the <embed> tag, for example:
    480  *       <embed id="nacl_module" dimensions="2">
    481  *     will produce two arguments, one named "id" and one named "dimensions".
    482  * @param[in] argv An array of argument values.  These are the values of the
    483  *     arguments listed in the <embed> tag.  In the above example, there will
    484  *     be two elements in this array, "nacl_module" and "2".  The indices of
    485  *     these values match the indices of the corresponding names in @a argn.
    486  * @return @a PP_TRUE on success.
    487  */
    488 static PP_Bool Instance_DidCreate(PP_Instance instance,
    489                                   uint32_t argc,
    490                                   const char* argn[],
    491                                   const char* argv[]) {
    492   g_instance = instance;
    493   LoadURL(instance, "hello.raw", Loaded, &g_TextureData);
    494   LoadURL(instance, "vertex_shader_es2.vert", Loaded, &g_VShaderData);
    495   LoadURL(instance, "fragment_shader_es2.frag", Loaded, &g_FShaderData);
    496   g_quadVertices = BuildCube();
    497   return PP_TRUE;
    498 }
    499 
    500 /**
    501  * Called when the NaCl module is destroyed. This will always be called,
    502  * even if DidCreate returned failure. This routine should deallocate any data
    503  * associated with the instance.
    504  * @param[in] instance The identifier of the instance representing this NaCl
    505  *     module.
    506  */
    507 static void Instance_DidDestroy(PP_Instance instance) {
    508   delete[] g_TextureData;
    509   delete[] g_VShaderData;
    510   delete[] g_FShaderData;
    511   delete[] g_quadVertices;
    512 }
    513 
    514 /**
    515  * Called when the position, the size, or the clip rect of the element in the
    516  * browser that corresponds to this NaCl module has changed.
    517  * @param[in] instance The identifier of the instance representing this NaCl
    518  *     module.
    519  * @param[in] position The location on the page of this NaCl module. This is
    520  *     relative to the top left corner of the viewport, which changes as the
    521  *     page is scrolled.
    522  * @param[in] clip The visible region of the NaCl module. This is relative to
    523  *     the top left of the plugin's coordinate system (not the page).  If the
    524  *     plugin is invisible, @a clip will be (0, 0, 0, 0).
    525  */
    526 static void Instance_DidChangeView(PP_Instance instance,
    527                                    PP_Resource view_resource) {
    528   if (g_context == 0) {
    529     InitGL();
    530     MainLoop(NULL, 0);
    531   }
    532 }
    533 
    534 /**
    535  * Notification that the given NaCl module has gained or lost focus.
    536  * Having focus means that keyboard events will be sent to the NaCl module
    537  * represented by @a instance. A NaCl module's default condition is that it
    538  * will not have focus.
    539  *
    540  * Note: clicks on NaCl modules will give focus only if you handle the
    541  * click event. You signal if you handled it by returning @a true from
    542  * HandleInputEvent. Otherwise the browser will bubble the event and give
    543  * focus to the element on the page that actually did end up consuming it.
    544  * If you're not getting focus, check to make sure you're returning true from
    545  * the mouse click in HandleInputEvent.
    546  * @param[in] instance The identifier of the instance representing this NaCl
    547  *     module.
    548  * @param[in] has_focus Indicates whether this NaCl module gained or lost
    549  *     event focus.
    550  */
    551 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {}
    552 
    553 /**
    554  * Handler that gets called after a full-frame module is instantiated based on
    555  * registered MIME types.  This function is not called on NaCl modules.  This
    556  * function is essentially a place-holder for the required function pointer in
    557  * the PPP_Instance structure.
    558  * @param[in] instance The identifier of the instance representing this NaCl
    559  *     module.
    560  * @param[in] url_loader A PP_Resource an open PPB_URLLoader instance.
    561  * @return PP_FALSE.
    562  */
    563 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
    564                                            PP_Resource url_loader) {
    565   /* NaCl modules do not need to handle the document load function. */
    566   return PP_FALSE;
    567 }
    568 
    569 /**
    570  * Entry points for the module.
    571  * Initialize needed interfaces: PPB_Core, PPB_Messaging and PPB_Var.
    572  * @param[in] a_module_id module ID
    573  * @param[in] get_browser pointer to PPB_GetInterface
    574  * @return PP_OK on success, any other value on failure.
    575  */
    576 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
    577                                        PPB_GetInterface get_browser) {
    578   ppb_core_interface = (PPB_Core*)(get_browser(PPB_CORE_INTERFACE));
    579   ppb_instance_interface = (PPB_Instance*)get_browser(PPB_INSTANCE_INTERFACE);
    580   ppb_messaging_interface =
    581       (PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE));
    582   ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE));
    583   ppb_urlloader_interface =
    584       (PPB_URLLoader*)(get_browser(PPB_URLLOADER_INTERFACE));
    585   ppb_urlrequestinfo_interface =
    586       (PPB_URLRequestInfo*)(get_browser(PPB_URLREQUESTINFO_INTERFACE));
    587   ppb_g3d_interface = (PPB_Graphics3D*)get_browser(PPB_GRAPHICS_3D_INTERFACE);
    588   if (!glInitializePPAPI(get_browser))
    589     return PP_ERROR_FAILED;
    590   return PP_OK;
    591 }
    592 
    593 /**
    594  * Returns an interface pointer for the interface of the given name, or NULL
    595  * if the interface is not supported.
    596  * @param[in] interface_name name of the interface
    597  * @return pointer to the interface
    598  */
    599 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
    600   if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
    601     static PPP_Instance instance_interface = {
    602       &Instance_DidCreate,
    603       &Instance_DidDestroy,
    604       &Instance_DidChangeView,
    605       &Instance_DidChangeFocus,
    606       &Instance_HandleDocumentLoad,
    607     };
    608     return &instance_interface;
    609   }
    610   return NULL;
    611 }
    612 
    613 /**
    614  * Called before the plugin module is unloaded.
    615  */
    616 PP_EXPORT void PPP_ShutdownModule() {}
    617