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.
5 // This example program is based on Simple_VertexShader.c from:
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
17 #include "ppapi/examples/compositor/spinning_cube.h"
25 #include "ppapi/lib/gl/include/GLES2/gl2.h"
29 const float kPi
= 3.14159265359f
;
31 int GenerateCube(GLuint
*vbo_vertices
,
32 GLuint
*vbo_indices
) {
33 const int num_indices
= 36;
35 const GLfloat cube_vertices
[] = {
46 const GLushort cube_indices
[] = {
62 glGenBuffers(1, vbo_vertices
);
63 glBindBuffer(GL_ARRAY_BUFFER
, *vbo_vertices
);
64 glBufferData(GL_ARRAY_BUFFER
,
65 sizeof(cube_vertices
),
68 glBindBuffer(GL_ARRAY_BUFFER
, 0);
72 glGenBuffers(1, vbo_indices
);
73 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, *vbo_indices
);
74 glBufferData(GL_ELEMENT_ARRAY_BUFFER
,
78 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, 0);
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
);
91 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &compiled
);
94 glDeleteShader(shader
);
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
);
108 GLuint fragment_shader
= LoadShader(GL_FRAGMENT_SHADER
,
109 fragment_shader_source
);
110 if (!fragment_shader
) {
111 glDeleteShader(vertex_shader
);
115 GLuint program_object
= glCreateProgram();
116 glAttachShader(program_object
, vertex_shader
);
117 glAttachShader(program_object
, fragment_shader
);
119 glLinkProgram(program_object
);
121 glDeleteShader(vertex_shader
);
122 glDeleteShader(fragment_shader
);
125 glGetProgramiv(program_object
, GL_LINK_STATUS
, &linked
);
128 glDeleteProgram(program_object
);
132 return program_object
;
144 memset(this, 0x0, sizeof(ESMatrix
));
147 void LoadIdentity() {
155 void Multiply(ESMatrix
* a
, ESMatrix
* b
) {
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]);
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]);
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]);
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]);
181 void Frustum(float left
,
187 float delta_x
= right
- left
;
188 float delta_y
= top
- bottom
;
189 float delta_z
= far_z
- near_z
;
191 if ((near_z
<= 0.0f
) ||
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
;
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
;
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
;
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
;
213 Multiply(&frust
, this);
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
);
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
;
229 void Rotate(GLfloat angle
, GLfloat x
, GLfloat y
, GLfloat z
) {
230 GLfloat mag
= sqrtf(x
* x
+ y
* y
+ z
* z
);
232 GLfloat sin_angle
= sinf(angle
* kPi
/ 180.0f
);
233 GLfloat cos_angle
= cosf(angle
* kPi
/ 180.0f
);
235 GLfloat xx
, yy
, zz
, xy
, yz
, zx
, xs
, ys
, zs
;
236 GLfloat one_minus_cos
;
252 one_minus_cos
= 1.0f
- cos_angle
;
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
;
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
;
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
;
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
;
274 Multiply(&rotation
, this);
279 float RotationForTimeDelta(float delta_time
) {
280 return delta_time
* 40.0f
;
283 float RotationForDragDistance(float drag_distance
) {
284 return drag_distance
/ 5; // Arbitrary damping.
289 class SpinningCube::GLState
{
293 void OnGLContextLost();
295 GLfloat angle_
; // Survives losing the GL context.
297 GLuint program_object_
;
298 GLint position_location_
;
300 GLuint vbo_vertices_
;
303 ESMatrix mvp_matrix_
;
306 SpinningCube::GLState::GLState()
311 void SpinningCube::GLState::OnGLContextLost() {
313 position_location_
= 0;
320 SpinningCube::SpinningCube()
321 : initialized_(false),
324 state_(new GLState()),
325 fling_multiplier_(1.0f
),
327 state_
->angle_
= 45.0f
;
330 SpinningCube::~SpinningCube() {
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_
);
343 void SpinningCube::Init(uint32_t width
, uint32_t height
) {
349 const char vertext_shader_source
[] =
350 "uniform mat4 u_mvpMatrix; \n"
351 "attribute vec4 a_position; \n"
352 "varying vec4 v_color; \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"
362 const char fragment_shader_source
[] =
363 "precision mediump float; \n"
364 "varying vec4 v_color; \n"
367 " gl_FragColor = v_color; \n"
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_
);
379 glClearColor(0.0f
, 0.0f
, 0.0f
, 0.2f
);
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;
389 state_
->OnGLContextLost();
392 void SpinningCube::SetFlingMultiplier(float drag_distance
,
394 fling_multiplier_
= RotationForDragDistance(drag_distance
) /
395 RotationForTimeDelta(drag_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
;
404 // Arbitrary 50-step linear reduction in spin speed.
405 if (fling_multiplier_
> 1.0f
) {
407 std::max(1.0f
, fling_multiplier_
- (fling_multiplier_
- 1.0f
) / 50);
413 void SpinningCube::UpdateForDragDistance(float distance
) {
414 state_
->angle_
+= RotationForDragDistance(distance
);
415 if (state_
->angle_
>= 360.0f
)
416 state_
->angle_
-= 360.0f
;
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_
);
427 glBindBuffer(GL_ARRAY_BUFFER
, state_
->vbo_vertices_
);
428 glVertexAttribPointer(state_
->position_location_
,
431 GL_FALSE
, 3 * sizeof(GLfloat
),
433 glEnableVertexAttribArray(state_
->position_location_
);
435 glUniformMatrix4fv(state_
->mvp_location_
,
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_
,
446 void SpinningCube::Update() {
447 float aspect
= static_cast<GLfloat
>(width_
) / static_cast<GLfloat
>(height_
);
449 ESMatrix perspective
;
450 perspective
.LoadIdentity();
451 perspective
.Perspective(60.0f
, aspect
, 1.0f
, 20.0f
);
454 modelview
.LoadIdentity();
455 modelview
.Translate(0.0, 0.0, -2.0);
456 modelview
.Rotate(state_
->angle_
* direction_
, 1.0, 0.0, 1.0);
458 state_
->mvp_matrix_
.Multiply(&modelview
, &perspective
);