• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 // This example program is based on Simple_VertexShader.c from:
6 
7 //
8 // Book:      OpenGL(R) ES 2.0 Programming Guide
9 // Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
10 // ISBN-10:   0321502795
11 // ISBN-13:   9780321502797
12 // Publisher: Addison-Wesley Professional
13 // URLs:      http://safari.informit.com/9780321563835
14 //            http://www.opengles-book.com
15 //
16 
17 #include "ppapi/examples/compositor/spinning_cube.h"
18 
19 #include <math.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <algorithm>
24 
25 #include "ppapi/lib/gl/include/GLES2/gl2.h"
26 
27 namespace {
28 
29 const float kPi = 3.14159265359f;
30 
GenerateCube(GLuint * vbo_vertices,GLuint * vbo_indices)31 int GenerateCube(GLuint *vbo_vertices,
32                  GLuint *vbo_indices) {
33   const int num_indices = 36;
34 
35   const GLfloat cube_vertices[] = {
36     -0.5f, -0.5f, -0.5f,
37      0.5f, -0.5f, -0.5f,
38      0.5f, -0.5f,  0.5f,
39     -0.5f, -0.5f,  0.5f,
40     -0.5f,  0.5f, -0.5f,
41      0.5f,  0.5f, -0.5f,
42      0.5f,  0.5f,  0.5f,
43     -0.5f,  0.5f,  0.5f,
44   };
45 
46   const GLushort cube_indices[] = {
47     0, 2, 1,
48     0, 3, 2,
49     4, 5, 6,
50     4, 6, 7,
51     3, 6, 2,
52     3, 7, 6,
53     0, 1, 5,
54     0, 5, 4,
55     0, 7, 3,
56     0, 4, 7,
57     1, 2, 6,
58     1, 6, 5,
59   };
60 
61   if (vbo_vertices) {
62     glGenBuffers(1, vbo_vertices);
63     glBindBuffer(GL_ARRAY_BUFFER, *vbo_vertices);
64     glBufferData(GL_ARRAY_BUFFER,
65                  sizeof(cube_vertices),
66                  cube_vertices,
67                  GL_STATIC_DRAW);
68     glBindBuffer(GL_ARRAY_BUFFER, 0);
69   }
70 
71   if (vbo_indices) {
72     glGenBuffers(1, vbo_indices);
73     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *vbo_indices);
74     glBufferData(GL_ELEMENT_ARRAY_BUFFER,
75                  sizeof(cube_indices),
76                  cube_indices,
77                  GL_STATIC_DRAW);
78     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
79   }
80 
81   return num_indices;
82 }
83 
LoadShader(GLenum type,const char * shader_source)84 GLuint LoadShader(GLenum type,
85                   const char* shader_source) {
86   GLuint shader = glCreateShader(type);
87   glShaderSource(shader, 1, &shader_source, NULL);
88   glCompileShader(shader);
89 
90   GLint compiled = 0;
91   glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
92 
93   if (!compiled) {
94     glDeleteShader(shader);
95     return 0;
96   }
97 
98   return shader;
99 }
100 
LoadProgram(const char * vertext_shader_source,const char * fragment_shader_source)101 GLuint LoadProgram(const char* vertext_shader_source,
102                    const char* fragment_shader_source) {
103   GLuint vertex_shader = LoadShader(GL_VERTEX_SHADER,
104                                     vertext_shader_source);
105   if (!vertex_shader)
106     return 0;
107 
108   GLuint fragment_shader = LoadShader(GL_FRAGMENT_SHADER,
109                                       fragment_shader_source);
110   if (!fragment_shader) {
111     glDeleteShader(vertex_shader);
112     return 0;
113   }
114 
115   GLuint program_object = glCreateProgram();
116   glAttachShader(program_object, vertex_shader);
117   glAttachShader(program_object, fragment_shader);
118 
119   glLinkProgram(program_object);
120 
121   glDeleteShader(vertex_shader);
122   glDeleteShader(fragment_shader);
123 
124   GLint linked = 0;
125   glGetProgramiv(program_object, GL_LINK_STATUS, &linked);
126 
127   if (!linked) {
128     glDeleteProgram(program_object);
129     return 0;
130   }
131 
132   return program_object;
133 }
134 
135 class ESMatrix {
136  public:
137   GLfloat m[4][4];
138 
ESMatrix()139   ESMatrix() {
140     LoadZero();
141   }
142 
LoadZero()143   void LoadZero() {
144     memset(this, 0x0, sizeof(ESMatrix));
145   }
146 
LoadIdentity()147   void LoadIdentity() {
148     LoadZero();
149     m[0][0] = 1.0f;
150     m[1][1] = 1.0f;
151     m[2][2] = 1.0f;
152     m[3][3] = 1.0f;
153   }
154 
Multiply(ESMatrix * a,ESMatrix * b)155   void Multiply(ESMatrix* a, ESMatrix* b) {
156     ESMatrix result;
157     for (int i = 0; i < 4; ++i) {
158       result.m[i][0] = (a->m[i][0] * b->m[0][0]) +
159                        (a->m[i][1] * b->m[1][0]) +
160                        (a->m[i][2] * b->m[2][0]) +
161                        (a->m[i][3] * b->m[3][0]);
162 
163       result.m[i][1] = (a->m[i][0] * b->m[0][1]) +
164                        (a->m[i][1] * b->m[1][1]) +
165                        (a->m[i][2] * b->m[2][1]) +
166                        (a->m[i][3] * b->m[3][1]);
167 
168       result.m[i][2] = (a->m[i][0] * b->m[0][2]) +
169                        (a->m[i][1] * b->m[1][2]) +
170                        (a->m[i][2] * b->m[2][2]) +
171                        (a->m[i][3] * b->m[3][2]);
172 
173       result.m[i][3] = (a->m[i][0] * b->m[0][3]) +
174                        (a->m[i][1] * b->m[1][3]) +
175                        (a->m[i][2] * b->m[2][3]) +
176                        (a->m[i][3] * b->m[3][3]);
177     }
178     *this = result;
179   }
180 
Frustum(float left,float right,float bottom,float top,float near_z,float far_z)181   void Frustum(float left,
182                float right,
183                float bottom,
184                float top,
185                float near_z,
186                float far_z) {
187     float delta_x = right - left;
188     float delta_y = top - bottom;
189     float delta_z = far_z - near_z;
190 
191     if ((near_z <= 0.0f) ||
192         (far_z <= 0.0f) ||
193         (delta_z <= 0.0f) ||
194         (delta_y <= 0.0f) ||
195         (delta_y <= 0.0f))
196       return;
197 
198     ESMatrix frust;
199     frust.m[0][0] = 2.0f * near_z / delta_x;
200     frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
201 
202     frust.m[1][1] = 2.0f * near_z / delta_y;
203     frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
204 
205     frust.m[2][0] = (right + left) / delta_x;
206     frust.m[2][1] = (top + bottom) / delta_y;
207     frust.m[2][2] = -(near_z + far_z) / delta_z;
208     frust.m[2][3] = -1.0f;
209 
210     frust.m[3][2] = -2.0f * near_z * far_z / delta_z;
211     frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
212 
213     Multiply(&frust, this);
214   }
215 
Perspective(float fov_y,float aspect,float near_z,float far_z)216   void Perspective(float fov_y, float aspect, float near_z, float far_z) {
217     GLfloat frustum_h = tanf(fov_y / 360.0f * kPi) * near_z;
218     GLfloat frustum_w = frustum_h * aspect;
219     Frustum(-frustum_w, frustum_w, -frustum_h, frustum_h, near_z, far_z);
220   }
221 
Translate(GLfloat tx,GLfloat ty,GLfloat tz)222   void Translate(GLfloat tx, GLfloat ty, GLfloat tz) {
223     m[3][0] += m[0][0] * tx + m[1][0] * ty + m[2][0] * tz;
224     m[3][1] += m[0][1] * tx + m[1][1] * ty + m[2][1] * tz;
225     m[3][2] += m[0][2] * tx + m[1][2] * ty + m[2][2] * tz;
226     m[3][3] += m[0][3] * tx + m[1][3] * ty + m[2][3] * tz;
227   }
228 
Rotate(GLfloat angle,GLfloat x,GLfloat y,GLfloat z)229   void Rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
230     GLfloat mag = sqrtf(x * x + y * y + z * z);
231 
232     GLfloat sin_angle = sinf(angle * kPi / 180.0f);
233     GLfloat cos_angle = cosf(angle * kPi / 180.0f);
234     if (mag > 0.0f) {
235       GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs;
236       GLfloat one_minus_cos;
237       ESMatrix rotation;
238 
239       x /= mag;
240       y /= mag;
241       z /= mag;
242 
243       xx = x * x;
244       yy = y * y;
245       zz = z * z;
246       xy = x * y;
247       yz = y * z;
248       zx = z * x;
249       xs = x * sin_angle;
250       ys = y * sin_angle;
251       zs = z * sin_angle;
252       one_minus_cos = 1.0f - cos_angle;
253 
254       rotation.m[0][0] = (one_minus_cos * xx) + cos_angle;
255       rotation.m[0][1] = (one_minus_cos * xy) - zs;
256       rotation.m[0][2] = (one_minus_cos * zx) + ys;
257       rotation.m[0][3] = 0.0F;
258 
259       rotation.m[1][0] = (one_minus_cos * xy) + zs;
260       rotation.m[1][1] = (one_minus_cos * yy) + cos_angle;
261       rotation.m[1][2] = (one_minus_cos * yz) - xs;
262       rotation.m[1][3] = 0.0F;
263 
264       rotation.m[2][0] = (one_minus_cos * zx) - ys;
265       rotation.m[2][1] = (one_minus_cos * yz) + xs;
266       rotation.m[2][2] = (one_minus_cos * zz) + cos_angle;
267       rotation.m[2][3] = 0.0F;
268 
269       rotation.m[3][0] = 0.0F;
270       rotation.m[3][1] = 0.0F;
271       rotation.m[3][2] = 0.0F;
272       rotation.m[3][3] = 1.0F;
273 
274       Multiply(&rotation, this);
275     }
276   }
277 };
278 
RotationForTimeDelta(float delta_time)279 float RotationForTimeDelta(float delta_time) {
280   return delta_time * 40.0f;
281 }
282 
RotationForDragDistance(float drag_distance)283 float RotationForDragDistance(float drag_distance) {
284   return drag_distance / 5; // Arbitrary damping.
285 }
286 
287 }  // namespace
288 
289 class SpinningCube::GLState {
290  public:
291   GLState();
292 
293   void OnGLContextLost();
294 
295   GLfloat angle_;  // Survives losing the GL context.
296 
297   GLuint program_object_;
298   GLint position_location_;
299   GLint mvp_location_;
300   GLuint vbo_vertices_;
301   GLuint vbo_indices_;
302   int num_indices_;
303   ESMatrix mvp_matrix_;
304 };
305 
GLState()306 SpinningCube::GLState::GLState()
307     : angle_(0) {
308   OnGLContextLost();
309 }
310 
OnGLContextLost()311 void SpinningCube::GLState::OnGLContextLost() {
312   program_object_ = 0;
313   position_location_ = 0;
314   mvp_location_ = 0;
315   vbo_vertices_ = 0;
316   vbo_indices_ = 0;
317   num_indices_ = 0;
318 }
319 
SpinningCube()320 SpinningCube::SpinningCube()
321     : initialized_(false),
322       width_(0),
323       height_(0),
324       state_(new GLState()),
325       fling_multiplier_(1.0f),
326       direction_(1) {
327   state_->angle_ = 45.0f;
328 }
329 
~SpinningCube()330 SpinningCube::~SpinningCube() {
331   if (!initialized_)
332     return;
333   if (state_->vbo_vertices_)
334     glDeleteBuffers(1, &state_->vbo_vertices_);
335   if (state_->vbo_indices_)
336     glDeleteBuffers(1, &state_->vbo_indices_);
337   if (state_->program_object_)
338     glDeleteProgram(state_->program_object_);
339 
340   delete state_;
341 }
342 
Init(uint32_t width,uint32_t height)343 void SpinningCube::Init(uint32_t width, uint32_t height) {
344   width_ = width;
345   height_ = height;
346 
347   if (!initialized_) {
348     initialized_ = true;
349     const char vertext_shader_source[] =
350         "uniform mat4 u_mvpMatrix;                   \n"
351         "attribute vec4 a_position;                  \n"
352         "varying vec4 v_color;                       \n"
353         "void main()                                 \n"
354         "{                                           \n"
355         "   gl_Position = u_mvpMatrix * a_position;  \n"
356         "   v_color = vec4(a_position.x + 0.5,       \n"
357         "                  a_position.y + 0.5,       \n"
358         "                  a_position.z + 0.5,       \n"
359         "                  0.8);                     \n"
360         "}                                           \n";
361 
362     const char fragment_shader_source[] =
363         "precision mediump float;                    \n"
364         "varying vec4 v_color;                       \n"
365         "void main()                                 \n"
366         "{                                           \n"
367         "  gl_FragColor = v_color;                   \n"
368         "}                                           \n";
369 
370     state_->program_object_ = LoadProgram(
371         vertext_shader_source, fragment_shader_source);
372     state_->position_location_ = glGetAttribLocation(
373         state_->program_object_, "a_position");
374     state_->mvp_location_ = glGetUniformLocation(
375         state_->program_object_, "u_mvpMatrix");
376     state_->num_indices_ = GenerateCube(&state_->vbo_vertices_,
377                                         &state_->vbo_indices_);
378 
379     glClearColor(0.0f, 0.0f, 0.0f, 0.2f);
380   }
381 }
382 
OnGLContextLost()383 void SpinningCube::OnGLContextLost() {
384   // TODO(yzshen): Is it correct that in this case we don't need to do cleanup
385   // for program and buffers?
386   initialized_ = false;
387   height_ = 0;
388   width_ = 0;
389   state_->OnGLContextLost();
390 }
391 
SetFlingMultiplier(float drag_distance,float drag_time)392 void SpinningCube::SetFlingMultiplier(float drag_distance,
393                                       float drag_time) {
394   fling_multiplier_ = RotationForDragDistance(drag_distance) /
395       RotationForTimeDelta(drag_time);
396 
397 }
398 
UpdateForTimeDelta(float delta_time)399 void SpinningCube::UpdateForTimeDelta(float delta_time) {
400   state_->angle_ += RotationForTimeDelta(delta_time) * fling_multiplier_;
401   if (state_->angle_ >= 360.0f)
402     state_->angle_ -= 360.0f;
403 
404   // Arbitrary 50-step linear reduction in spin speed.
405   if (fling_multiplier_ > 1.0f) {
406     fling_multiplier_ =
407         std::max(1.0f, fling_multiplier_ - (fling_multiplier_ - 1.0f) / 50);
408   }
409 
410   Update();
411 }
412 
UpdateForDragDistance(float distance)413 void SpinningCube::UpdateForDragDistance(float distance) {
414   state_->angle_ += RotationForDragDistance(distance);
415   if (state_->angle_ >= 360.0f )
416     state_->angle_ -= 360.0f;
417 
418   Update();
419 }
420 
Draw()421 void SpinningCube::Draw() {
422   glViewport(0, 0, width_, height_);
423   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
424   glEnable(GL_DEPTH_TEST);
425   glUseProgram(state_->program_object_);
426 
427   glBindBuffer(GL_ARRAY_BUFFER, state_->vbo_vertices_);
428   glVertexAttribPointer(state_->position_location_,
429                         3,
430                         GL_FLOAT,
431                         GL_FALSE, 3 * sizeof(GLfloat),
432                         0);
433   glEnableVertexAttribArray(state_->position_location_);
434 
435   glUniformMatrix4fv(state_->mvp_location_,
436                      1,
437                      GL_FALSE,
438                      (GLfloat*) &state_->mvp_matrix_.m[0][0]);
439   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state_->vbo_indices_);
440   glDrawElements(GL_TRIANGLES,
441                  state_->num_indices_,
442                  GL_UNSIGNED_SHORT,
443                  0);
444 }
445 
Update()446 void SpinningCube::Update() {
447   float aspect = static_cast<GLfloat>(width_) / static_cast<GLfloat>(height_);
448 
449   ESMatrix perspective;
450   perspective.LoadIdentity();
451   perspective.Perspective(60.0f, aspect, 1.0f, 20.0f );
452 
453   ESMatrix modelview;
454   modelview.LoadIdentity();
455   modelview.Translate(0.0, 0.0, -2.0);
456   modelview.Rotate(state_->angle_ * direction_, 1.0, 0.0, 1.0);
457 
458   state_->mvp_matrix_.Multiply(&modelview, &perspective);
459 }
460