- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / gonacl_appengine / src / cube / cube.cc
1 // Copyright (c) 2013 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 #include <GLES2/gl2.h>
6 #include <math.h>
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include "matrix.h"
13 #include "ppapi/cpp/graphics_3d.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/module.h"
16 #include "ppapi/cpp/var.h"
17 #include "ppapi/cpp/var_array.h"
18 #include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
19 #include "ppapi/utility/completion_callback_factory.h"
20
21 #ifdef WIN32
22 #undef PostMessage
23 // Allow 'this' in initializer list
24 #pragma warning(disable : 4355)
25 #endif
26
27 extern const uint8_t kRLETextureData[];
28 extern const size_t kRLETextureDataLength;
29
30 namespace {
31
32 const float kMinFovY = 45.0f;
33 const float kZNear = 1.0f;
34 const float kZFar = 10.0f;
35 const float kCameraZ = -4.0f;
36 const float kXAngleDelta = 2.0f;
37 const float kYAngleDelta = 0.5f;
38
39 const size_t kTextureDataLength = 128 * 128 * 3;  // 128x128, 3 Bytes/pixel.
40
41 // The decompressed data is written here.
42 uint8_t g_texture_data[kTextureDataLength];
43
44 void DecompressTexture() {
45   // The image is first encoded with a very simple RLE scheme:
46   //   <value0> <count0> <value1> <count1> ...
47   // Because a <count> of 0 is useless, we use it to represent 256.
48   //
49   // It is then Base64 encoded to make it use only printable characters (it
50   // stores more easily in a source file that way).
51   //
52   // To decompress, we have to reverse the process.
53   static const uint8_t kBase64Decode[256] = {
54     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
55     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
56     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0, 63,
57    52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0,  0,  0,  0,
58     0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
59    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
60     0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
61    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
62   };
63   const uint8_t* input = &kRLETextureData[0];
64   const uint8_t* const input_end = &kRLETextureData[kRLETextureDataLength];
65   uint8_t* output = &g_texture_data[0];
66 #ifndef NDEBUG
67   const uint8_t* const output_end = &g_texture_data[kTextureDataLength];
68 #endif
69
70   uint8_t decoded[4];
71   int decoded_count = 0;
72
73   while (input < input_end || decoded_count > 0) {
74     if (decoded_count < 2) {
75       assert(input + 4 <= input_end);
76       // Grab four base-64 encoded (6-bit) bytes.
77       uint32_t data = 0;
78       data |= (kBase64Decode[*input++] << 18);
79       data |= (kBase64Decode[*input++] << 12);
80       data |= (kBase64Decode[*input++] <<  6);
81       data |= (kBase64Decode[*input++]      );
82       // And decode it to 3 (8-bit) bytes.
83       decoded[decoded_count++] = (data >> 16) & 0xff;
84       decoded[decoded_count++] = (data >>  8) & 0xff;
85       decoded[decoded_count++] = (data      ) & 0xff;
86
87       // = is the base64 end marker. Remove decoded bytes if we see any.
88       if (input[-1] == '=') decoded_count--;
89       if (input[-2] == '=') decoded_count--;
90     }
91
92     int value = decoded[0];
93     int count = decoded[1];
94     decoded_count -= 2;
95     // Move the other decoded bytes (if any) down.
96     decoded[0] = decoded[2];
97     decoded[1] = decoded[3];
98
99     // Expand the RLE data.
100     if (count == 0)
101       count = 256;
102     assert(output <= output_end);
103     memset(output, value, count);
104     output += count;
105   }
106   assert(output == output_end);
107 }
108
109 GLuint CompileShader(GLenum type, const char* data) {
110   GLuint shader = glCreateShader(type);
111   glShaderSource(shader, 1, &data, NULL);
112   glCompileShader(shader);
113
114   GLint compile_status;
115   glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
116   if (compile_status != GL_TRUE) {
117     // Shader failed to compile, let's see what the error is.
118     char buffer[1024];
119     GLsizei length;
120     glGetShaderInfoLog(shader, sizeof(buffer), &length, &buffer[0]);
121     fprintf(stderr, "Shader failed to compile: %s\n", buffer);
122     return 0;
123   }
124
125   return shader;
126 }
127
128 GLuint LinkProgram(GLuint frag_shader, GLuint vert_shader) {
129   GLuint program = glCreateProgram();
130   glAttachShader(program, frag_shader);
131   glAttachShader(program, vert_shader);
132   glLinkProgram(program);
133
134   GLint link_status;
135   glGetProgramiv(program, GL_LINK_STATUS, &link_status);
136   if (link_status != GL_TRUE) {
137     // Program failed to link, let's see what the error is.
138     char buffer[1024];
139     GLsizei length;
140     glGetProgramInfoLog(program, sizeof(buffer), &length, &buffer[0]);
141     fprintf(stderr, "Program failed to link: %s\n", buffer);
142     return 0;
143   }
144
145   return program;
146 }
147
148 const char kFragShaderSource[] =
149     "precision mediump float;\n"
150     "varying vec3 v_color;\n"
151     "varying vec2 v_texcoord;\n"
152     "uniform sampler2D u_texture;\n"
153     "void main() {\n"
154     "  gl_FragColor = texture2D(u_texture, v_texcoord);\n"
155     "  gl_FragColor += vec4(v_color, 1);\n"
156     "}\n";
157
158 const char kVertexShaderSource[] =
159     "uniform mat4 u_mvp;\n"
160     "attribute vec2 a_texcoord;\n"
161     "attribute vec3 a_color;\n"
162     "attribute vec4 a_position;\n"
163     "varying vec3 v_color;\n"
164     "varying vec2 v_texcoord;\n"
165     "void main() {\n"
166     "  gl_Position = u_mvp * a_position;\n"
167     "  v_color = a_color;\n"
168     "  v_texcoord = a_texcoord;\n"
169     "}\n";
170
171 struct Vertex {
172   float loc[3];
173   float color[3];
174   float tex[2];
175 };
176
177 const Vertex kCubeVerts[24] = {
178   // +Z (red arrow, black tip)
179   {{-1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}},
180   {{+1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}},
181   {{+1.0, +1.0, +1.0}, {0.5, 0.0, 0.0}, {0.0, 1.0}},
182   {{-1.0, +1.0, +1.0}, {0.5, 0.0, 0.0}, {1.0, 1.0}},
183
184   // +X (green arrow, black tip)
185   {{+1.0, -1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}},
186   {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}},
187   {{+1.0, +1.0, +1.0}, {0.0, 0.5, 0.0}, {0.0, 1.0}},
188   {{+1.0, -1.0, +1.0}, {0.0, 0.5, 0.0}, {1.0, 1.0}},
189
190   // +Y (blue arrow, black tip)
191   {{-1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}},
192   {{-1.0, +1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}},
193   {{+1.0, +1.0, +1.0}, {0.0, 0.0, 0.5}, {0.0, 1.0}},
194   {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.5}, {1.0, 1.0}},
195
196   // -Z (red arrow, red tip)
197   {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}},
198   {{-1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}},
199   {{-1.0, -1.0, -1.0}, {1.0, 0.0, 0.0}, {0.0, 0.0}},
200   {{+1.0, -1.0, -1.0}, {1.0, 0.0, 0.0}, {1.0, 0.0}},
201
202   // -X (green arrow, green tip)
203   {{-1.0, +1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}},
204   {{-1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}},
205   {{-1.0, -1.0, -1.0}, {0.0, 1.0, 0.0}, {0.0, 0.0}},
206   {{-1.0, +1.0, -1.0}, {0.0, 1.0, 0.0}, {1.0, 0.0}},
207
208   // -Y (blue arrow, blue tip)
209   {{+1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}},
210   {{+1.0, -1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}},
211   {{-1.0, -1.0, -1.0}, {0.0, 0.0, 1.0}, {0.0, 0.0}},
212   {{-1.0, -1.0, +1.0}, {0.0, 0.0, 1.0}, {1.0, 0.0}},
213 };
214
215 const GLubyte kCubeIndexes[36] = {
216    2,  1,  0,  3,  2,  0,
217    6,  5,  4,  7,  6,  4,
218   10,  9,  8, 11, 10,  8,
219   14, 13, 12, 15, 14, 12,
220   18, 17, 16, 19, 18, 16,
221   22, 21, 20, 23, 22, 20,
222 };
223
224 }  // namespace
225
226
227 class CubeInstance : public pp::Instance {
228  public:
229   explicit CubeInstance(PP_Instance instance)
230       : pp::Instance(instance),
231         callback_factory_(this),
232         width_(0),
233         height_(0),
234         frag_shader_(0),
235         vertex_shader_(0),
236         program_(0),
237         texture_loc_(0),
238         position_loc_(0),
239         color_loc_(0),
240         mvp_loc_(0),
241         x_angle_(0),
242         y_angle_(0),
243         animating_(true) {}
244
245   virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
246     return true;
247   }
248
249   virtual void DidChangeView(const pp::View& view) {
250     int32_t new_width = view.GetRect().width();
251     int32_t new_height = view.GetRect().height();
252
253     if (context_.is_null()) {
254       if (!InitGL(new_width, new_height)) {
255         // failed.
256         return;
257       }
258
259       InitShaders();
260       InitBuffers();
261       InitTexture();
262       MainLoop(0);
263     } else {
264       // Resize the buffers to the new size of the module.
265       int32_t result = context_.ResizeBuffers(new_width, new_height);
266       if (result < 0) {
267         fprintf(stderr,
268                 "Unable to resize buffers to %d x %d!\n",
269                 new_width,
270                 new_height);
271         return;
272       }
273     }
274
275     width_ = new_width;
276     height_ = new_height;
277     glViewport(0, 0, width_, height_);
278   }
279
280   virtual void HandleMessage(const pp::Var& message) {
281     // A bool message sets whether the cube is animating or not.
282     if (message.is_bool()) {
283       animating_ = message.AsBool();
284       return;
285     }
286
287     // An array message sets the current x and y rotation.
288     if (!message.is_array()) {
289       fprintf(stderr, "Expected array message.\n");
290       return;
291     }
292
293     pp::VarArray array(message);
294     if (array.GetLength() != 2) {
295       fprintf(stderr, "Expected array of length 2.\n");
296       return;
297     }
298
299     pp::Var x_angle_var = array.Get(0);
300     if (x_angle_var.is_int()) {
301       x_angle_ = x_angle_var.AsInt();
302     } else if (x_angle_var.is_double()) {
303       x_angle_ = x_angle_var.AsDouble();
304     } else {
305       fprintf(stderr, "Expected value to be an int or double.\n");
306     }
307
308     pp::Var y_angle_var = array.Get(1);
309     if (y_angle_var.is_int()) {
310       y_angle_ = y_angle_var.AsInt();
311     } else if (y_angle_var.is_double()) {
312       y_angle_ = y_angle_var.AsDouble();
313     } else {
314       fprintf(stderr, "Expected value to be an int or double.\n");
315     }
316   }
317
318  private:
319   bool InitGL(int32_t new_width, int32_t new_height) {
320     if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
321       fprintf(stderr, "Unable to initialize GL PPAPI!\n");
322       return false;
323     }
324
325     const int32_t attrib_list[] = {
326       PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
327       PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
328       PP_GRAPHICS3DATTRIB_WIDTH, new_width,
329       PP_GRAPHICS3DATTRIB_HEIGHT, new_height,
330       PP_GRAPHICS3DATTRIB_NONE
331     };
332
333     context_ = pp::Graphics3D(this, attrib_list);
334     if (!BindGraphics(context_)) {
335       fprintf(stderr, "Unable to bind 3d context!\n");
336       context_ = pp::Graphics3D();
337       glSetCurrentContextPPAPI(0);
338       return false;
339     }
340
341     glSetCurrentContextPPAPI(context_.pp_resource());
342     return true;
343   }
344
345   void InitShaders() {
346     frag_shader_ = CompileShader(GL_FRAGMENT_SHADER, kFragShaderSource);
347     if (!frag_shader_)
348       return;
349
350     vertex_shader_ = CompileShader(GL_VERTEX_SHADER, kVertexShaderSource);
351     if (!vertex_shader_)
352       return;
353
354     program_ = LinkProgram(frag_shader_, vertex_shader_);
355     if (!program_)
356       return;
357
358     texture_loc_ = glGetUniformLocation(program_, "u_texture");
359     position_loc_ = glGetAttribLocation(program_, "a_position");
360     texcoord_loc_ = glGetAttribLocation(program_, "a_texcoord");
361     color_loc_ = glGetAttribLocation(program_, "a_color");
362     mvp_loc_ = glGetUniformLocation(program_, "u_mvp");
363   }
364
365   void InitBuffers() {
366     glGenBuffers(1, &vertex_buffer_);
367     glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
368     glBufferData(GL_ARRAY_BUFFER, sizeof(kCubeVerts), &kCubeVerts[0],
369                  GL_STATIC_DRAW);
370
371     glGenBuffers(1, &index_buffer_);
372     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_);
373     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kCubeIndexes),
374                  &kCubeIndexes[0], GL_STATIC_DRAW);
375   }
376
377   void InitTexture() {
378     DecompressTexture();
379     glGenTextures(1, &texture_);
380     glBindTexture(GL_TEXTURE_2D, texture_);
381     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
382     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
383     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
384     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
385     glTexImage2D(GL_TEXTURE_2D,
386                  0,
387                  GL_RGB,
388                  128,
389                  128,
390                  0,
391                  GL_RGB,
392                  GL_UNSIGNED_BYTE,
393                  &g_texture_data[0]);
394   }
395
396   void Animate() {
397     if (animating_) {
398       x_angle_ = fmod(360.0f + x_angle_ + kXAngleDelta, 360.0f);
399       y_angle_ = fmod(360.0f + y_angle_ + kYAngleDelta, 360.0f);
400
401       // Send new values to JavaScript.
402       pp::VarArray array;
403       array.SetLength(2);
404       array.Set(0, x_angle_);
405       array.Set(1, y_angle_);
406       PostMessage(array);
407     }
408   }
409
410   void Render() {
411     glClearColor(0.5, 0.5, 0.5, 1);
412     glClearDepthf(1.0f);
413     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
414     glEnable(GL_DEPTH_TEST);
415
416     //set what program to use
417     glUseProgram(program_);
418     glActiveTexture(GL_TEXTURE0);
419     glBindTexture(GL_TEXTURE_2D, texture_);
420     glUniform1i(texture_loc_, 0);
421
422     //create our perspective matrix
423     float mvp[16];
424     float trs[16];
425     float rot[16];
426
427     identity_matrix(mvp);
428     const float aspect_ratio = static_cast<float>(width_) / height_;
429     float fovY = kMinFovY / aspect_ratio;
430     if (fovY < kMinFovY)
431       fovY = kMinFovY;
432
433     glhPerspectivef2(&mvp[0], fovY, aspect_ratio, kZNear, kZFar);
434
435     translate_matrix(0, 0, kCameraZ, trs);
436     rotate_matrix(x_angle_, y_angle_, 0.0f, rot);
437     multiply_matrix(trs, rot, trs);
438     multiply_matrix(mvp, trs, mvp);
439     glUniformMatrix4fv(mvp_loc_, 1, GL_FALSE, mvp);
440
441     //define the attributes of the vertex
442     glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
443     glVertexAttribPointer(position_loc_,
444                           3,
445                           GL_FLOAT,
446                           GL_FALSE,
447                           sizeof(Vertex),
448                           reinterpret_cast<void*>(offsetof(Vertex, loc)));
449     glEnableVertexAttribArray(position_loc_);
450     glVertexAttribPointer(color_loc_,
451                           3,
452                           GL_FLOAT,
453                           GL_FALSE,
454                           sizeof(Vertex),
455                           reinterpret_cast<void*>(offsetof(Vertex, color)));
456     glEnableVertexAttribArray(color_loc_);
457     glVertexAttribPointer(texcoord_loc_,
458                           2,
459                           GL_FLOAT,
460                           GL_FALSE,
461                           sizeof(Vertex),
462                           reinterpret_cast<void*>(offsetof(Vertex, tex)));
463     glEnableVertexAttribArray(texcoord_loc_);
464
465     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_);
466     glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, 0);
467   }
468
469   void MainLoop(int32_t) {
470     Animate();
471     Render();
472     context_.SwapBuffers(
473         callback_factory_.NewCallback(&CubeInstance::MainLoop));
474   }
475
476   pp::CompletionCallbackFactory<CubeInstance> callback_factory_;
477   pp::Graphics3D context_;
478   int32_t width_;
479   int32_t height_;
480   GLuint frag_shader_;
481   GLuint vertex_shader_;
482   GLuint program_;
483   GLuint vertex_buffer_;
484   GLuint index_buffer_;
485   GLuint texture_;
486
487   GLuint texture_loc_;
488   GLuint position_loc_;
489   GLuint texcoord_loc_;
490   GLuint color_loc_;
491   GLuint mvp_loc_;
492
493   float x_angle_;
494   float y_angle_;
495   bool animating_;
496 };
497
498 class CubeModule : public pp::Module {
499  public:
500   CubeModule() : pp::Module() {}
501   virtual ~CubeModule() {}
502
503   virtual pp::Instance* CreateInstance(PP_Instance instance) {
504     return new CubeInstance(instance);
505   }
506 };
507
508 namespace pp {
509 Module* CreateModule() { return new CubeModule(); }
510 }  // namespace pp