#include "shape.h" #include //#include #include "graphics/shader.h" using namespace Eigen; using namespace std; // ================== Constructor Shape::Shape() : m_surfaceVao(), m_surfaceVbo(), m_surfaceIbo(), m_numSurfaceVertices(), m_verticesSize(), m_red(), m_blue(), m_green(), m_alpha(), m_faces(), m_vertices(), m_anchors(), m_modelMatrix(Matrix4f::Identity()), lastSelected(-1) {} // ================== Initialization and Updating void Shape::init(const vector &vertices, const vector &triangles) { m_vertices.clear(); copy(vertices.begin(), vertices.end(), back_inserter(m_vertices)); vector verts; vector normals; vector colors; vector faces; faces.reserve(triangles.size()); for (int s = 0; s < triangles.size() * 3; s+=3) faces.push_back(Vector3i(s, s + 1, s + 2)); updateMesh(triangles, vertices, verts, normals, colors); glGenBuffers(1, &m_surfaceVbo); glGenBuffers(1, &m_surfaceIbo); glGenVertexArrays(1, &m_surfaceVao); glBindBuffer(GL_ARRAY_BUFFER, m_surfaceVbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * ((verts.size() * 3) + (normals.size() * 3) + (colors.size() * 3)), nullptr, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * verts.size() * 3, static_cast(verts.data())); glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * verts.size() * 3, sizeof(float) * normals.size() * 3, static_cast(normals.data())); glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * ((verts.size() * 3) + (normals.size() * 3)), sizeof(float) * colors.size() * 3, static_cast(colors.data())); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_surfaceIbo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * 3 * faces.size(), static_cast(faces.data()), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray(m_surfaceVao); glBindBuffer(GL_ARRAY_BUFFER, m_surfaceVbo); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, static_cast(0)); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(sizeof(float) * verts.size() * 3)); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(sizeof(float) * (verts.size() * 3 + colors.size() * 3))); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_surfaceIbo); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); m_numSurfaceVertices = faces.size() * 3; m_verticesSize = vertices.size(); m_faces = triangles; m_red = 0.5f + 0.5f * rand() / ((float) RAND_MAX); m_blue = 0.5f + 0.5f * rand() / ((float) RAND_MAX); m_green = 0.5f + 0.5f * rand() / ((float) RAND_MAX); m_alpha = 1.0f; } void Shape::setVertices(const vector &vertices) { m_vertices.clear(); copy(vertices.begin(), vertices.end(), back_inserter(m_vertices)); vector verts; vector normals; vector colors; updateMesh(m_faces, vertices, verts, normals, colors); glBindBuffer(GL_ARRAY_BUFFER, m_surfaceVbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * ((verts.size() * 3) + (normals.size() * 3) + (colors.size() * 3)), nullptr, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * verts.size() * 3, static_cast(verts.data())); glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * verts.size() * 3, sizeof(float) * normals.size() * 3, static_cast(normals.data())); glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * ((verts.size() * 3) + (normals.size() * 3)), sizeof(float) * colors.size() * 3, static_cast(colors.data())); glBindBuffer(GL_ARRAY_BUFFER, 0); } // ================== Model Matrix void Shape::setModelMatrix(const Affine3f &model) { m_modelMatrix = model.matrix(); } // ================== General Graphics Stuff void Shape::setColor(float r, float g, float b) { m_red = r; m_green = g; m_blue = b; } void Shape::draw(Shader *shader, GLenum mode) { Eigen::Matrix3f m3 = m_modelMatrix.topLeftCorner(3, 3); Eigen::Matrix3f inverseTransposeModel = m3.inverse().transpose(); switch(mode) { case GL_TRIANGLES: { shader->setUniform("wire", 0); shader->setUniform("model", m_modelMatrix); shader->setUniform("inverseTransposeModel", inverseTransposeModel); shader->setUniform("red", m_red); shader->setUniform("green", m_green); shader->setUniform("blue", m_blue); shader->setUniform("alpha", m_alpha); glBindVertexArray(m_surfaceVao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, ocean_floor_texture); shader->setUniform("sampler", 1); glDrawElements(mode, m_numSurfaceVertices, GL_UNSIGNED_INT, reinterpret_cast(0)); glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); break; } case GL_POINTS: { shader->setUniform("model", m_modelMatrix); shader->setUniform("inverseTransposeModel", inverseTransposeModel); glBindVertexArray(m_surfaceVao); glDrawElements(mode, m_numSurfaceVertices, GL_UNSIGNED_INT, reinterpret_cast(0)); glBindVertexArray(0); break; } } } SelectMode Shape::select(Shader *shader, int closest_vertex) { if (closest_vertex == -1) return SelectMode::None; bool vertexIsNowSelected = m_anchors.find(closest_vertex) == m_anchors.end(); if (vertexIsNowSelected) { m_anchors.insert(closest_vertex); } else { m_anchors.erase(closest_vertex); } selectHelper(); return vertexIsNowSelected ? SelectMode::Anchor : SelectMode::Unanchor; } bool Shape::selectWithSpecifiedMode(Shader *shader, int closest_vertex, SelectMode mode) { switch (mode) { case SelectMode::None: { return false; } case SelectMode::Anchor: { if (m_anchors.find(closest_vertex) != m_anchors.end()) return false; m_anchors.insert(closest_vertex); break; } case SelectMode::Unanchor: { if (m_anchors.find(closest_vertex) == m_anchors.end()) return false; m_anchors.erase(closest_vertex); break; } } selectHelper(); return true; } int Shape::getClosestVertex(Vector3f start, Vector3f ray, float threshold) { int closest_vertex = -1; int i = 0; float dist = numeric_limits::max(); ParametrizedLine line = ParametrizedLine::Through(start, start + ray); for (const Vector3f &v : m_vertices) { float d = line.distance(v); if (d= threshold) closest_vertex = -1; return closest_vertex; } bool Shape::getAnchorPos(int lastSelected, Eigen::Vector3f& pos, Eigen::Vector3f ray, Eigen::Vector3f start) { bool isAnchor = m_anchors.find(lastSelected) != m_anchors.end(); if (isAnchor) { Eigen::Vector3f oldPos = m_vertices[lastSelected]; Eigen::ParametrizedLine line = ParametrizedLine::Through(start, start+ray); pos = line.projection(oldPos); } return isAnchor; } // ================== Accessors const vector &Shape::getVertices() { return m_vertices; } const vector &Shape::getFaces() { return m_faces; } const unordered_set &Shape::getAnchors() { return m_anchors; } // ================== Helpers void Shape::selectHelper() { vector verts; vector normals; vector colors; updateMesh(m_faces, m_vertices, verts, normals, colors); glBindBuffer(GL_ARRAY_BUFFER, m_surfaceVbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * ((verts.size() * 3) + (normals.size() * 3) + (colors.size() * 3)), nullptr, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * verts.size() * 3, static_cast(verts.data())); glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * verts.size() * 3, sizeof(float) * normals.size() * 3, static_cast(normals.data())); glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * ((verts.size() * 3) + (normals.size() * 3)), sizeof(float) * colors.size() * 3, static_cast(colors.data())); glBindBuffer(GL_ARRAY_BUFFER, 0); } Vector3f Shape::getNormal(const Vector3i& face) { Vector3f& v1 = m_vertices[face[0]]; Vector3f& v2 = m_vertices[face[1]]; Vector3f& v3 = m_vertices[face[2]]; Vector3f e1 = v2 - v1; Vector3f e2 = v3 - v1; Vector3f n = e1.cross(e2); return n.normalized(); } void Shape::updateMesh(const std::vector &faces, const std::vector &vertices, std::vector& verts, std::vector& normals, std::vector& colors) { verts.reserve(faces.size() * 3); normals.reserve(faces.size() * 3); for (const Eigen::Vector3i& face : faces) { Vector3f n = getNormal(face); for (auto& v: {face[0], face[1], face[2]}) { normals.push_back(n); verts.push_back(vertices[v]); if (m_anchors.find(v) == m_anchors.end()) { colors.push_back(Vector3f(1,0,0)); } else { colors.push_back(Vector3f(0, 1 - m_green, 1 - m_blue)); } } } } void Shape::initGroundPlane(std::string texturePath, float depth, Shader* shader) { // Prepare filepath QString ocean_floor_filepath = QString(texturePath.c_str()); // TASK 1: Obtain image from filepath this->ocean_floor_image = QImage(ocean_floor_filepath); // TASK 2: Format image to fit OpenGL ocean_floor_image = ocean_floor_image.convertToFormat(QImage::Format_RGBA8888).mirrored(); auto bits = this->ocean_floor_image.bits(); auto dat = ocean_floor_image.data_ptr(); // TASK 3: Generate texture glGenTextures(1, &ocean_floor_texture); // TASK 9: Set the active texture slot to texture slot 0 glActiveTexture(GL_TEXTURE0); // TASK 4: Bind kitten texture glBindTexture(GL_TEXTURE_2D, ocean_floor_texture); // TASK 5: Load image into kitten texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ocean_floor_image.width(), ocean_floor_image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, ocean_floor_image.bits()); // TASK 6: Set min and mag filters' interpolation mode to linear glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // TASK 7: Unbind kitten texture glBindTexture(GL_TEXTURE_2D, 0); // TASK 10: set the texture.frag uniform for our texture glUseProgram(shader->id()); // glUniform1i(glGetUniformLocation(shader->id(), "sampler"), 0); shader->setUniform("sampler", 0); glUseProgram(0); }