268 lines
7.8 KiB
C++
268 lines
7.8 KiB
C++
// Copyright (c) 2011 The Native Client 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 "cube.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#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<GLfloat>(width_) / static_cast<GLfloat>(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
|