192 lines
4.5 KiB
C++

#include "Sphere.h"
#include <glm//gtc/constants.hpp>
#include <glm/vec3.hpp>
#include <glm/mat3x3.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_inverse.hpp>
Sphere::Sphere()
{
}
Sphere::~Sphere()
{
}
Sphere::Sphere(float rad, GLuint sl, GLuint st) :
radius(rad), slices(sl), stacks(st)
{
nVerts = (slices + 1) * (stacks + 1);
elements = (slices * 2 * (stacks - 1)) * 3;
// Verts
float * v = new float[3 * nVerts];
// Normals
float * n = new float[3 * nVerts];
// Tex coords
float * tex = new float[2 * nVerts]; //we don't use it now
// Index
unsigned int * el = new unsigned int[elements]; //index
// Generate the vertex data
generateVerts(v, n, tex, el);
//create vao, vbo and ibo here... (We didn't use std::vector here...)
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO_position);
glBindBuffer(GL_ARRAY_BUFFER, VBO_position);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * nVerts, v, GL_STATIC_DRAW);
glVertexAttribPointer(
0, //attr number = 0
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0);
glEnableVertexAttribArray(0); //attr number = 0
glGenBuffers(1, &VBO_normal);
glBindBuffer(GL_ARRAY_BUFFER, VBO_normal);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * nVerts, n, GL_STATIC_DRAW);
glVertexAttribPointer(
1,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0);
glEnableVertexAttribArray(1);
glGenBuffers(1, &VBO_tex);
glBindBuffer(GL_ARRAY_BUFFER, VBO_tex);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 2 * nVerts, tex, GL_STATIC_DRAW);
glVertexAttribPointer(
2,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0);
glEnableVertexAttribArray(2);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements * sizeof(GLuint), el, GL_STATIC_DRAW);
glBindVertexArray(0);
delete[] v;
delete[] n;
delete[] el;
delete[] tex;
}
void Sphere::draw(ShaderProgram *shader, glm::mat4x4 proj_matrix, glm::mat4x4 view_matrix)
{
_model.glPushMatrix();
effectTransformations();
glBindVertexArray(VAO);
glm::mat4 mvpMatrix = proj_matrix * view_matrix * _model.getMatrix();
glUniformMatrix4fv(shader->uniform("mvp"), 1, GL_FALSE, glm::value_ptr(mvpMatrix));
glm::mat4 modelview = view_matrix * _model.getMatrix();
glUniform4fv(shader->uniform("LightLocation"), 1, glm::value_ptr(view_matrix * glm::vec4(50, 50, 50, 1)));
glUniformMatrix4fv(shader->uniform("ModelViewMatrix"), 1, GL_FALSE, glm::value_ptr(modelview));
glm::mat4 inverseModelView = glm::inverse(modelview);
glm::mat3 normalMatrix = glm::mat3(glm::transpose(inverseModelView));
glUniformMatrix3fv(shader->uniform("NormalMatrix"), 1, GL_FALSE, glm::value_ptr(normalMatrix));
int size;
glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size / sizeof(GLuint), GL_UNSIGNED_INT, 0);
_model.glPopMatrix();
}
void Sphere::generateVerts(float * verts, float * norms, float * tex,
unsigned int * el)
{
// Generate positions and normals
GLfloat theta, phi;
GLfloat thetaFac = glm::two_pi<float>() / slices;
GLfloat phiFac = glm::pi<float>() / stacks;
GLfloat nx, ny, nz, s, t;
GLuint idx = 0, tIdx = 0;
for (GLuint i = 0; i <= slices; i++) {
theta = i * thetaFac;
s = (GLfloat)i / slices;
for (GLuint j = 0; j <= stacks; j++) {
phi = j * phiFac;
t = (GLfloat)j / stacks;
nx = sinf(phi) * cosf(theta);
ny = sinf(phi) * sinf(theta);
nz = cosf(phi);
verts[idx] = radius * nx; verts[idx + 1] = radius * ny; verts[idx + 2] = radius * nz;
norms[idx] = nx; norms[idx + 1] = ny; norms[idx + 2] = nz;
idx += 3;
tex[tIdx] = s;
tex[tIdx + 1] = t;
tIdx += 2;
}
}
// Generate the element list
idx = 0;
for (GLuint i = 0; i < slices; i++) {
GLuint stackStart = i * (stacks + 1);
GLuint nextStackStart = (i + 1) * (stacks + 1);
for (GLuint j = 0; j < stacks; j++) {
if (j == 0) {
el[idx] = stackStart;
el[idx + 1] = stackStart + 1;
el[idx + 2] = nextStackStart + 1;
idx += 3;
}
else if (j == stacks - 1) {
el[idx] = stackStart + j;
el[idx + 1] = stackStart + j + 1;
el[idx + 2] = nextStackStart + j;
idx += 3;
}
else {
el[idx] = stackStart + j;
el[idx + 1] = stackStart + j + 1;
el[idx + 2] = nextStackStart + j + 1;
el[idx + 3] = nextStackStart + j;
el[idx + 4] = stackStart + j;
el[idx + 5] = nextStackStart + j + 1;
idx += 6;
}
}
}
}
DrawableType Sphere::getType()
{
return DrawableType::SPHERE;
}
int Sphere::getVertexArrayHandle()
{
return this->VAO;
}