// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "ppapi/gles2/gl2ext_ppapi.h" #include "cube.h" #include "shader_util.h" #include "transforms.h" namespace tumbler { static const size_t kVertexCount = 24; static const int kIndexCount = 36; Cube::Cube(SharedOpenGLContext opengl_context) : opengl_context_(opengl_context), width_(1), height_(1) { eye_[0] = eye_[1] = 0.0f; eye_[2] = 2.0f; orientation_[0] = 0.0f; orientation_[1] = 0.0f; orientation_[2] = 0.0f; orientation_[3] = 1.0f; } Cube::~Cube() { glDeleteBuffers(3, cube_vbos_); glDeleteProgram(shader_program_object_); } void Cube::PrepareOpenGL() { CreateShaders(); CreateCube(); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glEnable(GL_DEPTH_TEST); } void Cube::Resize(int width, int height) { width_ = std::max(width, 1); height_ = std::max(height, 1); // Set the viewport glViewport(0, 0, width_, height_); // Compute the perspective projection matrix with a 60 degree FOV. GLfloat aspect = static_cast(width_) / static_cast(height_); transform_4x4::LoadIdentity(perspective_proj_); transform_4x4::Perspective(perspective_proj_, 60.0f, aspect, 1.0f, 20.0f); } void Cube::Draw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Compute a new model-view matrix, then use that to make the composite // model-view-projection matrix: MVP = MV . P. GLfloat model_view[16]; ComputeModelViewTransform(model_view); transform_4x4::Multiply(mvp_matrix_, model_view, perspective_proj_); glBindBuffer(GL_ARRAY_BUFFER, cube_vbos_[0]); glUseProgram(shader_program_object_); glEnableVertexAttribArray(position_location_); glVertexAttribPointer(position_location_, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), NULL); glEnableVertexAttribArray(color_location_); glBindBuffer(GL_ARRAY_BUFFER, cube_vbos_[1]); glVertexAttribPointer(color_location_, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), NULL); glUniformMatrix4fv(mvp_location_, 1, GL_FALSE, mvp_matrix_); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_vbos_[2]); glDrawElements(GL_TRIANGLES, kIndexCount, GL_UNSIGNED_SHORT, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } bool Cube::CreateShaders() { const char vertex_shader_src[] = "uniform mat4 u_mvpMatrix; \n" "attribute vec4 a_position; \n" "attribute vec3 a_color; \n" "varying lowp vec4 v_color; \n" "void main() \n" "{ \n" " v_color.xyz = a_color; \n" " v_color.w = 1.0; \n" " gl_Position = u_mvpMatrix * a_position; \n" "} \n"; const char fragment_shader_src[] = "varying lowp vec4 v_color; \n" "void main() \n" "{ \n" " gl_FragColor = v_color; \n" "} \n"; // Load the shaders and get a linked program object shader_program_object_ = shader_util::CreateProgramFromVertexAndFragmentShaders( vertex_shader_src, fragment_shader_src); if (shader_program_object_ == 0) return false; position_location_ = glGetAttribLocation(shader_program_object_, "a_position"); color_location_ = glGetAttribLocation(shader_program_object_, "a_color"); mvp_location_ = glGetUniformLocation(shader_program_object_, "u_mvpMatrix"); return true; } void Cube::CreateCube() { static const GLfloat cube_vertices[] = { // Vertex coordinates interleaved with color values // Bottom -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, // Top -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, // Back -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, // Front -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, // Left -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, // Right 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f }; static const GLfloat cube_colors[] = { // Vertex coordinates interleaved with color values // Bottom 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // Top 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // Back 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // Front 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, // Left 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, // Right 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 }; static const GLushort cube_indices[] = { // Bottom 0, 2, 1, 0, 3, 2, // Top 4, 5, 6, 4, 6, 7, // Back 8, 9, 10, 8, 10, 11, // Front 12, 15, 14, 12, 14, 13, // Left 16, 17, 18, 16, 18, 19, // Right 20, 23, 22, 20, 22, 21 }; // Generate the VBOs and upload them to the graphics context. glGenBuffers(3, cube_vbos_); glBindBuffer(GL_ARRAY_BUFFER, cube_vbos_[0]); glBufferData(GL_ARRAY_BUFFER, kVertexCount * sizeof(GLfloat) * 3, cube_vertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, cube_vbos_[1]); glBufferData(GL_ARRAY_BUFFER, kVertexCount * sizeof(GLfloat) * 3, cube_colors, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_vbos_[2]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, kIndexCount * sizeof(GL_UNSIGNED_SHORT), cube_indices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } void Cube::ComputeModelViewTransform(GLfloat* model_view) { // This method takes into account the possiblity that |orientation_| // might not be normalized. double sqrx = orientation_[0] * orientation_[0]; double sqry = orientation_[1] * orientation_[1]; double sqrz = orientation_[2] * orientation_[2]; double sqrw = orientation_[3] * orientation_[3]; double sqrLength = 1.0 / (sqrx + sqry + sqrz + sqrw); transform_4x4::LoadIdentity(model_view); model_view[0] = (sqrx - sqry - sqrz + sqrw) * sqrLength; model_view[5] = (-sqrx + sqry - sqrz + sqrw) * sqrLength; model_view[10] = (-sqrx - sqry + sqrz + sqrw) * sqrLength; double temp1 = orientation_[0] * orientation_[1]; double temp2 = orientation_[2] * orientation_[3]; model_view[1] = 2.0 * (temp1 + temp2) * sqrLength; model_view[4] = 2.0 * (temp1 - temp2) * sqrLength; temp1 = orientation_[0] * orientation_[2]; temp2 = orientation_[1] * orientation_[3]; model_view[2] = 2.0 * (temp1 - temp2) * sqrLength; model_view[8] = 2.0 * (temp1 + temp2) * sqrLength; temp1 = orientation_[1] * orientation_[2]; temp2 = orientation_[0] * orientation_[3]; model_view[6] = 2.0 * (temp1 + temp2) * sqrLength; model_view[9] = 2.0 * (temp1 - temp2) * sqrLength; model_view[3] = 0.0; model_view[7] = 0.0; model_view[11] = 0.0; // Concatenate the translation to the eye point. model_view[12] = -eye_[0]; model_view[13] = -eye_[1]; model_view[14] = -eye_[2]; model_view[15] = 1.0; } } // namespace tumbler