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