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