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