1656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// Copyright 2013 The Chromium Authors. All rights reserved.
2656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// Use of this source code is governed by a BSD-style license that can be
3656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// found in the LICENSE file.
4656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
5656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// This example program is based on Simple_VertexShader.c from:
6656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
7656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project//
8656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// Book:      OpenGL(R) ES 2.0 Programming Guide
9656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
10656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// ISBN-10:   0321502795
11656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// ISBN-13:   9780321502797
12656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// Publisher: Addison-Wesley Professional
13656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// URLs:      http://safari.informit.com/9780321563835
14656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project//            http://www.opengles-book.com
15656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project//
16656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
17656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "mojo/examples/sample_app/spinning_cube.h"
18656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
19656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include <math.h>
20656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include <stdlib.h>
21656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include <string.h>
22656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include <GLES2/gl2.h>
23656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include <GLES2/gl2ext.h>
24656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
25656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectnamespace examples {
26656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
27656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectnamespace {
28656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
29656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectconst float kPi = 3.14159265359f;
30656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
31656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectint GenerateCube(GLuint *vbo_vertices,
32656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                 GLuint *vbo_indices) {
33656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  const int num_indices = 36;
34656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
35656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  const GLfloat cube_vertices[] = {
36656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f, -0.5f, -0.5f,
37656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f, -0.5f,  0.5f,
38656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f, -0.5f,  0.5f,
39656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f, -0.5f, -0.5f,
40656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f,  0.5f, -0.5f,
41656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f,  0.5f,  0.5f,
42656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f,  0.5f,  0.5f,
43656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f,  0.5f, -0.5f,
44656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f, -0.5f, -0.5f,
45656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f,  0.5f, -0.5f,
46656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f,  0.5f, -0.5f,
47656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f, -0.5f, -0.5f,
48656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f, -0.5f, 0.5f,
49656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f,  0.5f, 0.5f,
50656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f,  0.5f, 0.5f,
51656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f, -0.5f, 0.5f,
52656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f, -0.5f, -0.5f,
53656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f, -0.5f,  0.5f,
54656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f,  0.5f,  0.5f,
55656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    -0.5f,  0.5f, -0.5f,
56656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f, -0.5f, -0.5f,
57656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f, -0.5f,  0.5f,
58656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f,  0.5f,  0.5f,
59656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0.5f,  0.5f, -0.5f,
60656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  };
61656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
62656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  const GLushort cube_indices[] = {
63656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0, 2, 1,
64656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    0, 3, 2,
65656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    4, 5, 6,
66656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    4, 6, 7,
67656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    8, 9, 10,
68656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    8, 10, 11,
69656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    12, 15, 14,
70656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    12, 14, 13,
71656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    16, 17, 18,
72656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    16, 18, 19,
73656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    20, 23, 22,
74656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    20, 22, 21
75656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  };
76656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
77656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (vbo_vertices) {
78656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glGenBuffers(1, vbo_vertices);
79656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glBindBuffer(GL_ARRAY_BUFFER, *vbo_vertices);
80656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glBufferData(GL_ARRAY_BUFFER,
81656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                 sizeof(cube_vertices),
82656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                 cube_vertices,
83656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                 GL_STATIC_DRAW);
84656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glBindBuffer(GL_ARRAY_BUFFER, 0);
85656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
86656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
87656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (vbo_indices) {
88656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glGenBuffers(1, vbo_indices);
89656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *vbo_indices);
90656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
91656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                 sizeof(cube_indices),
92656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                 cube_indices,
93656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                 GL_STATIC_DRAW);
94656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
95656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
96656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
97656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  return num_indices;
98656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
99656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
100656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source ProjectGLuint LoadShader(GLenum type,
101656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                  const char* shader_source) {
102656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  GLuint shader = glCreateShader(type);
103656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glShaderSource(shader, 1, &shader_source, NULL);
104656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glCompileShader(shader);
105656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
106656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  GLint compiled = 0;
107656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
108656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
109656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (!compiled) {
110656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glDeleteShader(shader);
111656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    return 0;
112656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
113656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
114656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  return shader;
115656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
116656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
117656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source ProjectGLuint LoadProgram(const char* vertext_shader_source,
118656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                   const char* fragment_shader_source) {
119656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  GLuint vertex_shader = LoadShader(GL_VERTEX_SHADER,
120656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                                    vertext_shader_source);
121656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (!vertex_shader)
122656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    return 0;
123656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
124656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  GLuint fragment_shader = LoadShader(GL_FRAGMENT_SHADER,
125656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                                      fragment_shader_source);
126656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (!fragment_shader) {
127656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glDeleteShader(vertex_shader);
128656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    return 0;
129656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
130656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
131656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  GLuint program_object = glCreateProgram();
132656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glAttachShader(program_object, vertex_shader);
133656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glAttachShader(program_object, fragment_shader);
134656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
135656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glLinkProgram(program_object);
136656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
137656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glDeleteShader(vertex_shader);
138656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glDeleteShader(fragment_shader);
139656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
140656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  GLint linked = 0;
141656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  glGetProgramiv(program_object, GL_LINK_STATUS, &linked);
142656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
143656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (!linked) {
144656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    glDeleteProgram(program_object);
145656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    return 0;
146656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
147656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
148656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  return program_object;
149656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
150656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
151656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectclass ESMatrix {
152656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project public:
153656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  GLfloat m[4][4];
154656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
155656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  ESMatrix() {
156656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    LoadZero();
157656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
158656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
159656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  void LoadZero() {
160656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    memset(this, 0x0, sizeof(ESMatrix));
161656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
162656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
163656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  void LoadIdentity() {
164656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    LoadZero();
165656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    m[0][0] = 1.0f;
166656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    m[1][1] = 1.0f;
167656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    m[2][2] = 1.0f;
168656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    m[3][3] = 1.0f;
169656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
170656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
171656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  void Multiply(ESMatrix* a, ESMatrix* b) {
172656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    ESMatrix result;
173656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    for (int i = 0; i < 4; ++i) {
174656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      result.m[i][0] = (a->m[i][0] * b->m[0][0]) +
175656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][1] * b->m[1][0]) +
176656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][2] * b->m[2][0]) +
177656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][3] * b->m[3][0]);
178656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
179656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      result.m[i][1] = (a->m[i][0] * b->m[0][1]) +
180656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][1] * b->m[1][1]) +
181656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][2] * b->m[2][1]) +
182656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][3] * b->m[3][1]);
183656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
184656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      result.m[i][2] = (a->m[i][0] * b->m[0][2]) +
185656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][1] * b->m[1][2]) +
186656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][2] * b->m[2][2]) +
187656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][3] * b->m[3][2]);
188656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
189656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      result.m[i][3] = (a->m[i][0] * b->m[0][3]) +
190656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][1] * b->m[1][3]) +
191656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][2] * b->m[2][3]) +
192656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                       (a->m[i][3] * b->m[3][3]);
193656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    }
194656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    *this = result;
195656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
196656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
197656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  void Frustum(float left,
198656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project               float right,
199656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project               float bottom,
200656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project               float top,
201656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project               float near_z,
202656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project               float far_z) {
203656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    float delta_x = right - left;
204656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    float delta_y = top - bottom;
205656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    float delta_z = far_z - near_z;
206656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
207656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    if ((near_z <= 0.0f) ||
208656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project        (far_z <= 0.0f) ||
209656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project        (delta_z <= 0.0f) ||
210656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project        (delta_y <= 0.0f) ||
211656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project        (delta_y <= 0.0f))
212656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      return;
213656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
214656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    ESMatrix frust;
215656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[0][0] = 2.0f * near_z / delta_x;
216656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
217656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
218656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[1][1] = 2.0f * near_z / delta_y;
219656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
220656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
221656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[2][0] = (right + left) / delta_x;
222656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[2][1] = (top + bottom) / delta_y;
223656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[2][2] = -(near_z + far_z) / delta_z;
224656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[2][3] = -1.0f;
225656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
226656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[3][2] = -2.0f * near_z * far_z / delta_z;
227656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
228656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
229656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    Multiply(&frust, this);
230656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
231656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
232656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  void Perspective(float fov_y, float aspect, float near_z, float far_z) {
233656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    GLfloat frustum_h = tanf(fov_y / 360.0f * kPi) * near_z;
234656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    GLfloat frustum_w = frustum_h * aspect;
235656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    Frustum(-frustum_w, frustum_w, -frustum_h, frustum_h, near_z, far_z);
236656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
237656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
238656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  void Translate(GLfloat tx, GLfloat ty, GLfloat tz) {
239656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    m[3][0] += m[0][0] * tx + m[1][0] * ty + m[2][0] * tz;
240656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    m[3][1] += m[0][1] * tx + m[1][1] * ty + m[2][1] * tz;
241656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    m[3][2] += m[0][2] * tx + m[1][2] * ty + m[2][2] * tz;
242656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    m[3][3] += m[0][3] * tx + m[1][3] * ty + m[2][3] * tz;
243656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
244656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
245656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  void Rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
246656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    GLfloat mag = sqrtf(x * x + y * y + z * z);
247656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
248656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    GLfloat sin_angle = sinf(angle * kPi / 180.0f);
249656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    GLfloat cos_angle = cosf(angle * kPi / 180.0f);
250656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    if (mag > 0.0f) {
251656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs;
252656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      GLfloat one_minus_cos;
253656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      ESMatrix rotation;
254656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
255      x /= mag;
256      y /= mag;
257      z /= mag;
258
259      xx = x * x;
260      yy = y * y;
261      zz = z * z;
262      xy = x * y;
263      yz = y * z;
264      zx = z * x;
265      xs = x * sin_angle;
266      ys = y * sin_angle;
267      zs = z * sin_angle;
268      one_minus_cos = 1.0f - cos_angle;
269
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;
274
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;
279
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;
284
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;
289
290      Multiply(&rotation, this);
291    }
292  }
293};
294
295float RotationForTimeDelta(float delta_time) {
296  return delta_time * 40.0f;
297}
298
299float RotationForDragDistance(float drag_distance) {
300  return drag_distance / 5; // Arbitrary damping.
301}
302
303}  // namespace
304
305class SpinningCube::GLState {
306 public:
307  GLState();
308
309  void OnGLContextLost();
310
311  GLfloat angle_;  // Survives losing the GL context.
312
313  GLuint program_object_;
314  GLint position_location_;
315  GLint mvp_location_;
316  GLint color_location_;
317  GLuint vbo_vertices_;
318  GLuint vbo_indices_;
319  int num_indices_;
320  ESMatrix mvp_matrix_;
321};
322
323SpinningCube::GLState::GLState()
324    : angle_(0) {
325  OnGLContextLost();
326}
327
328void SpinningCube::GLState::OnGLContextLost() {
329  program_object_ = 0;
330  position_location_ = 0;
331  mvp_location_ = 0;
332  color_location_ = 0;
333  vbo_vertices_ = 0;
334  vbo_indices_ = 0;
335  num_indices_ = 0;
336}
337
338SpinningCube::SpinningCube()
339    : initialized_(false),
340      width_(0),
341      height_(0),
342      state_(new GLState()),
343      fling_multiplier_(1.0f),
344      direction_(1),
345      color_() {
346  state_->angle_ = 45.0f;
347  set_color(0.0, 1.0, 0.0);
348}
349
350SpinningCube::~SpinningCube() {
351  if (!initialized_)
352    return;
353  if (state_->vbo_vertices_)
354    glDeleteBuffers(1, &state_->vbo_vertices_);
355  if (state_->vbo_indices_)
356    glDeleteBuffers(1, &state_->vbo_indices_);
357  if (state_->program_object_)
358    glDeleteProgram(state_->program_object_);
359}
360
361void SpinningCube::Init(uint32_t width, uint32_t height) {
362  width_ = width;
363  height_ = height;
364
365  const char vertext_shader_source[] =
366      "uniform mat4 u_mvpMatrix;                   \n"
367      "attribute vec4 a_position;                  \n"
368      "void main()                                 \n"
369      "{                                           \n"
370      "   gl_Position = u_mvpMatrix * a_position;  \n"
371      "}                                           \n";
372
373  const char fragment_shader_source[] =
374      "precision mediump float;                            \n"
375      "uniform vec4 u_color;                               \n"
376      "void main()                                         \n"
377      "{                                                   \n"
378      "  gl_FragColor = u_color;                           \n"
379      "}                                                   \n";
380
381  state_->program_object_ = LoadProgram(
382      vertext_shader_source, fragment_shader_source);
383  state_->position_location_ = glGetAttribLocation(
384      state_->program_object_, "a_position");
385  state_->mvp_location_ = glGetUniformLocation(
386      state_->program_object_, "u_mvpMatrix");
387  state_->color_location_ = glGetUniformLocation(
388      state_->program_object_, "u_color");
389  state_->num_indices_ = GenerateCube(
390      &state_->vbo_vertices_, &state_->vbo_indices_);
391
392  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
393  initialized_ = true;
394}
395
396void SpinningCube::OnGLContextLost() {
397  initialized_ = false;
398  height_ = 0;
399  width_ = 0;
400  state_->OnGLContextLost();
401}
402
403void SpinningCube::SetFlingMultiplier(float drag_distance,
404                                      float drag_time) {
405  fling_multiplier_ = RotationForDragDistance(drag_distance) /
406      RotationForTimeDelta(drag_time);
407
408}
409
410void SpinningCube::UpdateForTimeDelta(float delta_time) {
411  state_->angle_ += RotationForTimeDelta(delta_time) * fling_multiplier_;
412  if (state_->angle_ >= 360.0f)
413    state_->angle_ -= 360.0f;
414
415  // Arbitrary 50-step linear reduction in spin speed.
416  if (fling_multiplier_ > 1.0f) {
417    fling_multiplier_ =
418        std::max(1.0f, fling_multiplier_ - (fling_multiplier_ - 1.0f) / 50);
419  }
420
421  Update();
422}
423
424void SpinningCube::UpdateForDragDistance(float distance) {
425  state_->angle_ += RotationForDragDistance(distance);
426  if (state_->angle_ >= 360.0f )
427    state_->angle_ -= 360.0f;
428
429  Update();
430}
431
432void SpinningCube::Draw() {
433  glViewport(0, 0, width_, height_);
434  glClear(GL_COLOR_BUFFER_BIT);
435  glUseProgram(state_->program_object_);
436  glBindBuffer(GL_ARRAY_BUFFER, state_->vbo_vertices_);
437  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state_->vbo_indices_);
438  glVertexAttribPointer(state_->position_location_,
439                           3,
440                           GL_FLOAT,
441                           GL_FALSE, 3 * sizeof(GLfloat),
442                           0);
443  glEnableVertexAttribArray(state_->position_location_);
444  glUniformMatrix4fv(state_->mvp_location_,
445                        1,
446                        GL_FALSE,
447                        (GLfloat*) &state_->mvp_matrix_.m[0][0]);
448  glUniform4f(state_->color_location_, color_[0], color_[1], color_[2], 1.0);
449  glDrawElements(GL_TRIANGLES,
450                    state_->num_indices_,
451                    GL_UNSIGNED_SHORT,
452                    0);
453}
454
455void SpinningCube::Update() {
456  float aspect = static_cast<GLfloat>(width_) / static_cast<GLfloat>(height_);
457
458  ESMatrix perspective;
459  perspective.LoadIdentity();
460  perspective.Perspective(60.0f, aspect, 1.0f, 20.0f );
461
462  ESMatrix modelview;
463  modelview.LoadIdentity();
464  modelview.Translate(0.0, 0.0, -2.0);
465  modelview.Rotate(state_->angle_ * direction_, 1.0, 0.0, 1.0);
466
467  state_->mvp_matrix_.Multiply(&modelview, &perspective);
468}
469
470}  // namespace examples
471