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/gles2_spinning_cube/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
[] = {
62 const GLushort cube_indices
[] = {
78 glGenBuffers(1, vbo_vertices
);
79 glBindBuffer(GL_ARRAY_BUFFER
, *vbo_vertices
);
80 glBufferData(GL_ARRAY_BUFFER
,
81 sizeof(cube_vertices
),
84 glBindBuffer(GL_ARRAY_BUFFER
, 0);
88 glGenBuffers(1, vbo_indices
);
89 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, *vbo_indices
);
90 glBufferData(GL_ELEMENT_ARRAY_BUFFER
,
94 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, 0);
100 GLuint
LoadShader(GLenum type
,
101 const char* shader_source
) {
102 GLuint shader
= glCreateShader(type
);
103 glShaderSource(shader
, 1, &shader_source
, NULL
);
104 glCompileShader(shader
);
107 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &compiled
);
110 glDeleteShader(shader
);
117 GLuint
LoadProgram(const char* vertext_shader_source
,
118 const char* fragment_shader_source
) {
119 GLuint vertex_shader
= LoadShader(GL_VERTEX_SHADER
,
120 vertext_shader_source
);
124 GLuint fragment_shader
= LoadShader(GL_FRAGMENT_SHADER
,
125 fragment_shader_source
);
126 if (!fragment_shader
) {
127 glDeleteShader(vertex_shader
);
131 GLuint program_object
= glCreateProgram();
132 glAttachShader(program_object
, vertex_shader
);
133 glAttachShader(program_object
, fragment_shader
);
135 glLinkProgram(program_object
);
137 glDeleteShader(vertex_shader
);
138 glDeleteShader(fragment_shader
);
141 glGetProgramiv(program_object
, GL_LINK_STATUS
, &linked
);
144 glDeleteProgram(program_object
);
148 return program_object
;
160 memset(this, 0x0, sizeof(ESMatrix
));
163 void LoadIdentity() {
171 void Multiply(ESMatrix
* a
, ESMatrix
* b
) {
173 for (int i
= 0; i
< 4; ++i
) {
174 result
.m
[i
][0] = (a
->m
[i
][0] * b
->m
[0][0]) +
175 (a
->m
[i
][1] * b
->m
[1][0]) +
176 (a
->m
[i
][2] * b
->m
[2][0]) +
177 (a
->m
[i
][3] * b
->m
[3][0]);
179 result
.m
[i
][1] = (a
->m
[i
][0] * b
->m
[0][1]) +
180 (a
->m
[i
][1] * b
->m
[1][1]) +
181 (a
->m
[i
][2] * b
->m
[2][1]) +
182 (a
->m
[i
][3] * b
->m
[3][1]);
184 result
.m
[i
][2] = (a
->m
[i
][0] * b
->m
[0][2]) +
185 (a
->m
[i
][1] * b
->m
[1][2]) +
186 (a
->m
[i
][2] * b
->m
[2][2]) +
187 (a
->m
[i
][3] * b
->m
[3][2]);
189 result
.m
[i
][3] = (a
->m
[i
][0] * b
->m
[0][3]) +
190 (a
->m
[i
][1] * b
->m
[1][3]) +
191 (a
->m
[i
][2] * b
->m
[2][3]) +
192 (a
->m
[i
][3] * b
->m
[3][3]);
197 void Frustum(float left
,
203 float delta_x
= right
- left
;
204 float delta_y
= top
- bottom
;
205 float delta_z
= far_z
- near_z
;
207 if ((near_z
<= 0.0f
) ||
215 frust
.m
[0][0] = 2.0f
* near_z
/ delta_x
;
216 frust
.m
[0][1] = frust
.m
[0][2] = frust
.m
[0][3] = 0.0f
;
218 frust
.m
[1][1] = 2.0f
* near_z
/ delta_y
;
219 frust
.m
[1][0] = frust
.m
[1][2] = frust
.m
[1][3] = 0.0f
;
221 frust
.m
[2][0] = (right
+ left
) / delta_x
;
222 frust
.m
[2][1] = (top
+ bottom
) / delta_y
;
223 frust
.m
[2][2] = -(near_z
+ far_z
) / delta_z
;
224 frust
.m
[2][3] = -1.0f
;
226 frust
.m
[3][2] = -2.0f
* near_z
* far_z
/ delta_z
;
227 frust
.m
[3][0] = frust
.m
[3][1] = frust
.m
[3][3] = 0.0f
;
229 Multiply(&frust
, this);
232 void Perspective(float fov_y
, float aspect
, float near_z
, float far_z
) {
233 GLfloat frustum_h
= tanf(fov_y
/ 360.0f
* kPi
) * near_z
;
234 GLfloat frustum_w
= frustum_h
* aspect
;
235 Frustum(-frustum_w
, frustum_w
, -frustum_h
, frustum_h
, near_z
, far_z
);
238 void Translate(GLfloat tx
, GLfloat ty
, GLfloat tz
) {
239 m
[3][0] += m
[0][0] * tx
+ m
[1][0] * ty
+ m
[2][0] * tz
;
240 m
[3][1] += m
[0][1] * tx
+ m
[1][1] * ty
+ m
[2][1] * tz
;
241 m
[3][2] += m
[0][2] * tx
+ m
[1][2] * ty
+ m
[2][2] * tz
;
242 m
[3][3] += m
[0][3] * tx
+ m
[1][3] * ty
+ m
[2][3] * tz
;
245 void Rotate(GLfloat angle
, GLfloat x
, GLfloat y
, GLfloat z
) {
246 GLfloat mag
= sqrtf(x
* x
+ y
* y
+ z
* z
);
248 GLfloat sin_angle
= sinf(angle
* kPi
/ 180.0f
);
249 GLfloat cos_angle
= cosf(angle
* kPi
/ 180.0f
);
251 GLfloat xx
, yy
, zz
, xy
, yz
, zx
, xs
, ys
, zs
;
252 GLfloat one_minus_cos
;
268 one_minus_cos
= 1.0f
- cos_angle
;
270 rotation
.m
[0][0] = (one_minus_cos
* xx
) + cos_angle
;
271 rotation
.m
[0][1] = (one_minus_cos
* xy
) - zs
;
272 rotation
.m
[0][2] = (one_minus_cos
* zx
) + ys
;
273 rotation
.m
[0][3] = 0.0F
;
275 rotation
.m
[1][0] = (one_minus_cos
* xy
) + zs
;
276 rotation
.m
[1][1] = (one_minus_cos
* yy
) + cos_angle
;
277 rotation
.m
[1][2] = (one_minus_cos
* yz
) - xs
;
278 rotation
.m
[1][3] = 0.0F
;
280 rotation
.m
[2][0] = (one_minus_cos
* zx
) - ys
;
281 rotation
.m
[2][1] = (one_minus_cos
* yz
) + xs
;
282 rotation
.m
[2][2] = (one_minus_cos
* zz
) + cos_angle
;
283 rotation
.m
[2][3] = 0.0F
;
285 rotation
.m
[3][0] = 0.0F
;
286 rotation
.m
[3][1] = 0.0F
;
287 rotation
.m
[3][2] = 0.0F
;
288 rotation
.m
[3][3] = 1.0F
;
290 Multiply(&rotation
, this);
295 float RotationForTimeDelta(float delta_time
) {
296 return delta_time
* 40.0f
;
299 float RotationForDragDistance(float drag_distance
) {
300 return drag_distance
/ 5; // Arbitrary damping.
305 class SpinningCube::GLState
{
309 void OnGLContextLost();
311 GLfloat angle_
; // Survives losing the GL context.
313 GLuint program_object_
;
314 GLint position_location_
;
316 GLuint vbo_vertices_
;
319 ESMatrix mvp_matrix_
;
322 SpinningCube::GLState::GLState()
327 void SpinningCube::GLState::OnGLContextLost() {
329 position_location_
= 0;
336 SpinningCube::SpinningCube()
337 : initialized_(false),
340 state_(new GLState()),
341 fling_multiplier_(1.0f
),
343 state_
->angle_
= 45.0f
;
346 SpinningCube::~SpinningCube() {
349 if (state_
->vbo_vertices_
)
350 glDeleteBuffers(1, &state_
->vbo_vertices_
);
351 if (state_
->vbo_indices_
)
352 glDeleteBuffers(1, &state_
->vbo_indices_
);
353 if (state_
->program_object_
)
354 glDeleteProgram(state_
->program_object_
);
359 void SpinningCube::Init(uint32_t width
, uint32_t height
) {
365 const char vertext_shader_source
[] =
366 "uniform mat4 u_mvpMatrix; \n"
367 "attribute vec4 a_position; \n"
370 " gl_Position = u_mvpMatrix * a_position; \n"
373 const char fragment_shader_source
[] =
374 "precision mediump float; \n"
377 " gl_FragColor = vec4( 0.0, 0.0, 1.0, 1.0 ); \n"
380 state_
->program_object_
= LoadProgram(
381 vertext_shader_source
, fragment_shader_source
);
382 state_
->position_location_
= glGetAttribLocation(
383 state_
->program_object_
, "a_position");
384 state_
->mvp_location_
= glGetUniformLocation(
385 state_
->program_object_
, "u_mvpMatrix");
386 state_
->num_indices_
= GenerateCube(
387 &state_
->vbo_vertices_
, &state_
->vbo_indices_
);
389 glClearColor(0.0f
, 0.0f
, 0.0f
, 0.0f
);
393 void SpinningCube::OnGLContextLost() {
394 // TODO(yzshen): Is it correct that in this case we don't need to do cleanup
395 // for program and buffers?
396 initialized_
= false;
399 state_
->OnGLContextLost();
402 void SpinningCube::SetFlingMultiplier(float drag_distance
,
404 fling_multiplier_
= RotationForDragDistance(drag_distance
) /
405 RotationForTimeDelta(drag_time
);
409 void SpinningCube::UpdateForTimeDelta(float delta_time
) {
410 state_
->angle_
+= RotationForTimeDelta(delta_time
) * fling_multiplier_
;
411 if (state_
->angle_
>= 360.0f
)
412 state_
->angle_
-= 360.0f
;
414 // Arbitrary 50-step linear reduction in spin speed.
415 if (fling_multiplier_
> 1.0f
) {
417 std::max(1.0f
, fling_multiplier_
- (fling_multiplier_
- 1.0f
) / 50);
423 void SpinningCube::UpdateForDragDistance(float distance
) {
424 state_
->angle_
+= RotationForDragDistance(distance
);
425 if (state_
->angle_
>= 360.0f
)
426 state_
->angle_
-= 360.0f
;
431 void SpinningCube::Draw() {
432 glViewport(0, 0, width_
, height_
);
433 glClear(GL_COLOR_BUFFER_BIT
);
434 glUseProgram(state_
->program_object_
);
435 glBindBuffer(GL_ARRAY_BUFFER
, state_
->vbo_vertices_
);
436 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, state_
->vbo_indices_
);
437 glVertexAttribPointer(state_
->position_location_
,
440 GL_FALSE
, 3 * sizeof(GLfloat
),
442 glEnableVertexAttribArray(state_
->position_location_
);
443 glUniformMatrix4fv(state_
->mvp_location_
,
446 (GLfloat
*) &state_
->mvp_matrix_
.m
[0][0]);
447 glDrawElements(GL_TRIANGLES
,
448 state_
->num_indices_
,
453 void SpinningCube::Update() {
454 float aspect
= static_cast<GLfloat
>(width_
) / static_cast<GLfloat
>(height_
);
456 ESMatrix perspective
;
457 perspective
.LoadIdentity();
458 perspective
.Perspective(60.0f
, aspect
, 1.0f
, 20.0f
);
461 modelview
.LoadIdentity();
462 modelview
.Translate(0.0, 0.0, -2.0);
463 modelview
.Rotate(state_
->angle_
* direction_
, 1.0, 0.0, 1.0);
465 state_
->mvp_matrix_
.Multiply(&modelview
, &perspective
);