/* Copyright (c) 2017,2018 Regents of the University of Minnesota. All Rights Reserved. See corresponding header file for details. */ #include "quick_shapes.h" #include "platform.h" #include #include #include #include "gfxmath.h" namespace mingfx { #define PI 3.14159265359f #define TWOPI 6.28318530718f // Helper datastructure for building shapes algorithmically class Vertex { public: Vertex(GLfloat xx, GLfloat yy, GLfloat zz, GLfloat nnx, GLfloat nny, GLfloat nnz) : x(xx), y(yy), z(zz), nx(nnx), ny(nny), nz(nnz) {} GLfloat x; GLfloat y; GLfloat z; GLfloat nx; GLfloat ny; GLfloat nz; }; QuickShapes::QuickShapes() { } QuickShapes::~QuickShapes() { } // ------------ CUBE ------------ void QuickShapes::initCube() { GLfloat vertices[] = { 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,-1.0f, 1.0f, // v0-v1-v2 (front) -1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // v2-v3-v0 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f,-1.0f,-1.0f, // v0-v3-v4 (right) 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, // v4-v5-v0 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f,-1.0f, // v0-v5-v6 (top) -1.0f, 1.0f,-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // v6-v1-v0 -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, -1.0f,-1.0f,-1.0f, // v1-v6-v7 (left) -1.0f,-1.0f,-1.0f, -1.0f,-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // v7-v2-v1.0 -1.0f,-1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f,-1.0f, 1.0f, // v7-v4-v3 (bottom) 1.0f,-1.0f, 1.0f, -1.0f,-1.0f, 1.0f, -1.0f,-1.0f,-1.0f, // v3-v2-v7 1.0f,-1.0f,-1.0f, -1.0f,-1.0f,-1.0f, -1.0f, 1.0f,-1.0f, // v4-v7-v6 (back) -1.0f, 1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f // v6-v5-v4 }; GLfloat normals[] = { 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2 (front) 0, 0, 1, 0, 0, 1, 0, 0, 1, // v2-v3-v0 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4 (right) 1, 0, 0, 1, 0, 0, 1, 0, 0, // v4-v5-v0 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6 (top) 0, 1, 0, 0, 1, 0, 0, 1, 0, // v6-v1-v0 -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7 (left) -1, 0, 0, -1, 0, 0, -1, 0, 0, // v7-v2-v1 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3 (bottom) 0,-1, 0, 0,-1, 0, 0,-1, 0, // v3-v2-v7 0, 0,-1, 0, 0,-1, 0, 0,-1, // v4-v7-v6 (back) 0, 0,-1, 0, 0,-1, 0, 0,-1 // v6-v5-v4 }; cubeMesh_.SetVertices(vertices, 36); cubeMesh_.SetNormals(normals, 36); cubeMesh_.UpdateGPUMemory(); } void QuickShapes::DrawCube(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, const Matrix4 &projectionMatrix, const Color &color) { if (cubeMesh_.num_vertices() == 0) { initCube(); } defaultMaterial_.ambient_reflectance = color; defaultMaterial_.diffuse_reflectance = color; defaultMaterial_.surface_texture = emptyTex_; defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &cubeMesh_, defaultMaterial_); } // ------------ SQUARE ------------ void QuickShapes::initSquare() { GLfloat vertices[] = { 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,-1.0f, -1.0f, 0.0f,-1.0f, // v0-v5-v6 (top) -1.0f, 0.0f,-1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f // v6-v1-v0 }; GLfloat normals[] = { 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 }; GLfloat texcoords[] = { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }; squareMesh_.SetVertices(vertices, 6); squareMesh_.SetNormals(normals, 6); squareMesh_.SetTexCoords(0, texcoords, 6); squareMesh_.UpdateGPUMemory(); } void QuickShapes::DrawSquare(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, const Matrix4 &projectionMatrix, const Color &color) { if (squareMesh_.num_vertices() == 0) { initSquare(); } defaultMaterial_.ambient_reflectance = color; defaultMaterial_.diffuse_reflectance = color; defaultMaterial_.surface_texture = emptyTex_; defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &squareMesh_, defaultMaterial_); } void QuickShapes::DrawSquare(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, const Matrix4 &projectionMatrix, const Color &color, const Texture2D &tex) { if (squareMesh_.num_vertices() == 0) { initSquare(); } defaultMaterial_.ambient_reflectance = color; defaultMaterial_.diffuse_reflectance = color; defaultMaterial_.surface_texture = tex; defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &squareMesh_, defaultMaterial_); } // ------------ CYLINDER ------------ void QuickShapes::initCyl() { std::vector verts; Vertex top(0,1,0, 0,1,0); Vertex bot(0,-1,0, 0,-1,0); const int nslices = 20; for (int s=1; s vertices; std::vector normals; for (int i=0; i verts; Vertex top(0,1,0, 0,1,0); Vertex bot(0,-1,0, 0,-1,0); const int nslices = 20; for (int s=1; s vertices; std::vector normals; for (int i = 0; i < verts.size(); i++) { vertices.push_back(Point3(verts[i].x, verts[i].y, verts[i].z)); normals.push_back(Vector3(verts[i].nx, verts[i].ny, verts[i].nz)); } coneMesh_.SetVertices(vertices); coneMesh_.SetNormals(normals); coneMesh_.UpdateGPUMemory(); } void QuickShapes::DrawCone(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, const Matrix4 &projectionMatrix, const Color &color) { if (coneMesh_.num_vertices() == 0) { initCone(); } defaultMaterial_.ambient_reflectance = color; defaultMaterial_.diffuse_reflectance = color; defaultMaterial_.surface_texture = emptyTex_; defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &coneMesh_, defaultMaterial_); } // ------------ SPHERE ------------ void QuickShapes::initSph() { std::vector verts; Vertex top(0,1,0, 0,1,0); Vertex bot(0,-1,0, 0,-1,0); const int nslices = 40; const int nstacks = 40; for (int s=1; s vertices; std::vector normals; for (int i = 0; i < verts.size(); i++) { vertices.push_back(Point3(verts[i].x, verts[i].y, verts[i].z)); normals.push_back(Vector3(verts[i].nx, verts[i].ny, verts[i].nz)); } sphereMesh_.SetVertices(vertices); sphereMesh_.SetNormals(normals); sphereMesh_.UpdateGPUMemory(); } void QuickShapes::DrawSphere(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, const Matrix4 &projectionMatrix, const Color &color) { if (sphereMesh_.num_vertices() == 0) { initSph(); } defaultMaterial_.ambient_reflectance = color; defaultMaterial_.diffuse_reflectance = color; defaultMaterial_.surface_texture = emptyTex_; defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &sphereMesh_, defaultMaterial_); } // ------------ BRUSH ------------ void QuickShapes::initBrush() { // Raw vertices -- points that make up the brush geometry const GLfloat v[19][3] = { { 0.5f, 0.0f, 0.0f}, // 0 {-0.5f, 0.0f, 0.0f}, // 1 { 0.5f, 0.1f, 0.25f}, // 2 {-0.5f, 0.1f, 0.25f}, // 3 { 0.5f, 0.1f, 0.75f}, // 4 {-0.5f, 0.1f, 0.75f}, // 5 { 0.1f, 0.06f, 1.0f}, // 6 {-0.1f, 0.06f, 1.0f}, // 7 { 0.15f, 0.1f, 1.75f}, // 8 {-0.15f, 0.1f, 1.75f}, // 9 { 0.0f, 0.0f, 1.85f}, // 10 { 0.5f, -0.1f, 0.25f}, // 11 {-0.5f, -0.1f, 0.25f}, // 12 { 0.5f, -0.1f, 0.75f}, // 13 {-0.5f, -0.1f, 0.75f}, // 14 { 0.1f, -0.06f, 1.0f}, // 15 {-0.1f, -0.06f, 1.0f}, // 16 { 0.15f, -0.1f, 1.75f}, // 17 {-0.15f, -0.1f, 1.75f} // 18 }; // Vertices arranged into triangles const GLfloat verts[34][3][3] = { // top {{v[0][0], v[0][1], v[0][2]}, {v[1][0], v[1][1], v[1][2]}, {v[2][0], v[2][1], v[2][2]}}, {{v[1][0], v[1][1], v[1][2]}, {v[3][0], v[3][1], v[3][2]}, {v[2][0], v[2][1], v[2][2]}}, {{v[2][0], v[2][1], v[2][2]}, {v[3][0], v[3][1], v[3][2]}, {v[4][0], v[4][1], v[4][2]}}, {{v[3][0], v[3][1], v[3][2]}, {v[5][0], v[5][1], v[5][2]}, {v[4][0], v[4][1], v[4][2]}}, {{v[4][0], v[4][1], v[4][2]}, {v[5][0], v[5][1], v[5][2]}, {v[6][0], v[6][1], v[6][2]}}, {{v[5][0], v[5][1], v[5][2]}, {v[7][0], v[7][1], v[7][2]}, {v[6][0], v[6][1], v[6][2]}}, {{v[6][0], v[6][1], v[6][2]}, {v[7][0], v[7][1], v[7][2]}, {v[8][0], v[8][1], v[8][2]}}, {{v[7][0], v[7][1], v[7][2]}, {v[9][0], v[9][1], v[9][2]}, {v[8][0], v[8][1], v[8][2]}}, {{v[8][0], v[8][1], v[8][2]}, {v[9][0], v[9][1], v[9][2]}, {v[10][0], v[10][1], v[10][2]}}, // bottom {{v[0][0], v[0][1], v[0][2]}, {v[12][0], v[12][1], v[12][2]}, {v[1][0], v[1][1], v[1][2]}}, {{v[11][0], v[11][1], v[11][2]}, {v[12][0], v[12][1], v[12][2]}, {v[0][0], v[0][1], v[0][2]}}, {{v[11][0], v[11][1], v[11][2]}, {v[14][0], v[14][1], v[14][2]}, {v[12][0], v[12][1], v[12][2]}}, {{v[13][0], v[13][1], v[13][2]}, {v[14][0], v[14][1], v[14][2]}, {v[11][0], v[11][1], v[11][2]}}, {{v[13][0], v[13][1], v[13][2]}, {v[16][0], v[16][1], v[16][2]}, {v[14][0], v[14][1], v[14][2]}}, {{v[15][0], v[15][1], v[15][2]}, {v[16][0], v[16][1], v[16][2]}, {v[13][0], v[13][1], v[13][2]}}, {{v[15][0], v[15][1], v[15][2]}, {v[18][0], v[18][1], v[18][2]}, {v[16][0], v[16][1], v[16][2]}}, {{v[17][0], v[17][1], v[17][2]}, {v[18][0], v[18][1], v[18][2]}, {v[15][0], v[15][1], v[15][2]}}, {{v[18][0], v[18][1], v[18][2]}, {v[17][0], v[17][1], v[17][2]}, {v[10][0], v[10][1], v[10][2]}}, // one side {{v[11][0], v[11][1], v[11][2]}, {v[0][0], v[0][1], v[0][2]}, {v[2][0], v[2][1], v[2][2]}}, {{v[11][0], v[11][1], v[11][2]}, {v[2][0], v[2][1], v[2][2]}, {v[4][0], v[4][1], v[4][2]}}, {{v[4][0], v[4][1], v[4][2]}, {v[13][0], v[13][1], v[13][2]}, {v[11][0], v[11][1], v[11][2]}}, {{v[13][0], v[13][1], v[13][2]}, {v[4][0], v[4][1], v[4][2]}, {v[6][0], v[6][1], v[6][2]}}, {{v[6][0], v[6][1], v[6][2]}, {v[15][0], v[15][1], v[15][2]}, {v[13][0], v[13][1], v[13][2]}}, {{v[15][0], v[15][1], v[15][2]}, {v[6][0], v[6][1], v[6][2]}, {v[8][0], v[8][1], v[8][2]}}, {{v[8][0], v[8][1], v[8][2]}, {v[17][0], v[17][1], v[17][2]}, {v[15][0], v[15][1], v[15][2]}}, {{v[17][0], v[17][1], v[17][2]}, {v[8][0], v[8][1], v[8][2]}, {v[10][0], v[10][1], v[10][2]}}, // other side {{v[3][0], v[3][1], v[3][2]}, {v[1][0], v[1][1], v[1][2]}, {v[12][0], v[12][1], v[12][2]}}, {{v[3][0], v[3][1], v[3][2]}, {v[12][0], v[12][1], v[12][2]}, {v[14][0], v[14][1], v[14][2]}}, {{v[14][0], v[14][1], v[14][2]}, {v[5][0], v[5][1], v[5][2]}, {v[3][0], v[3][1], v[3][2]}}, {{v[5][0], v[5][1], v[5][2]}, {v[14][0], v[14][1], v[14][2]}, {v[16][0], v[16][1], v[16][2]}}, {{v[16][0], v[16][1], v[16][2]}, {v[7][0], v[7][1], v[7][2]}, {v[5][0], v[5][1], v[5][2]}}, {{v[7][0], v[7][1], v[7][2]}, {v[16][0], v[16][1], v[16][2]}, {v[18][0], v[18][1], v[18][2]}}, {{v[18][0], v[18][1], v[18][2]}, {v[9][0], v[9][1], v[9][2]}, {v[7][0], v[7][1], v[7][2]}}, {{v[9][0], v[9][1], v[9][2]}, {v[18][0], v[18][1], v[18][2]}, {v[10][0], v[10][1], v[10][2]}} }; // Normals defined so as to make each face of the brush a flat surface const GLfloat norms[34][3][3] = { // top {{0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}}, {{0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}, {0.0f, 0.93f, -0.37f}}, {{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, {{0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, {{0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}}, {{0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}, {0.0f, 0.988f, 0.158f}}, {{0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}}, {{0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}, {0.0f, 0.999f, -0.0533f}}, {{0.0f, 0.709f, 0.709f}, {0.0f, 0.709f, 0.709f}, {0.0f, 0.709f, 0.709f}}, // bottom {{0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}}, {{0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}, {0.0f, -0.93f, -0.37f}}, {{0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}}, {{0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f}}, {{0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}}, {{0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}, {0.0f, -0.988f, 0.158f}}, {{0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}}, {{0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}, {0.0f, -0.999f, -0.0533f}}, {{0.0f, -0.709f, 0.709f}, {0.0f, -0.709f, 0.709f}, {0.0f, -0.709f, 0.709f}}, // one side {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, {{0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}}, {{0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}, {0.848f, 0.0f, 0.530f}}, {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, {{1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}, {{0.709f, 0.0f, 0.709f}, {0.709f, 0.0f, 0.709f}, {0.709f, 0.0f, 0.709f}}, // other side {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, {{-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}}, {{-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}, {-0.848f, 0.0f, 0.530f}}, {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, {{-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}}, {{-0.709f, 0.0f, 0.709f}, {-0.709f, 0.0f, 0.709f}, {-0.709f, 0.0f, 0.709f}} }; brushMesh_.SetVertices((float*)verts, 102); brushMesh_.SetNormals((float*)norms, 102); brushMesh_.UpdateGPUMemory(); } void QuickShapes::DrawBrush(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, const Matrix4 &projectionMatrix, const Color &color) { if (brushMesh_.num_vertices() == 0) { initBrush(); } defaultMaterial_.ambient_reflectance = color; defaultMaterial_.diffuse_reflectance = color; defaultMaterial_.surface_texture = emptyTex_; defaultShader_.Draw(modelMatrix, viewMatrix, projectionMatrix, &brushMesh_, defaultMaterial_); } // ---------------- void QuickShapes::DrawLineSegment(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, const Matrix4 &projectionMatrix, const Color &color, const Point3 &p1, const Point3 &p2, float radius) { Matrix4 S = Matrix4::Scale(Vector3(radius, 0.5f*(p2-p1).Length(), radius)); Vector3 y = (p2-p1).ToUnit(); Vector3 z = Vector3(1,0,0).Cross(y).ToUnit(); if (z == Vector3(0,0,0)) { z = Vector3(0,0,1).Cross(y).ToUnit(); } Vector3 x = y.Cross(z); Matrix4 R = Matrix4::FromRowMajorElements( x[0], y[0], z[0], 0, x[1], y[1], z[1], 0, x[2], y[2], z[2], 0, 0, 0, 0, 1 ); Matrix4 T = Matrix4::Translation(0.5 * Vector3(p1[0]+p2[0], p1[1]+p2[1], p1[2]+p2[2])); Matrix4 M = T * R * S; DrawCylinder(modelMatrix * M, viewMatrix, projectionMatrix, color); } void QuickShapes::DrawLines(const Matrix4 &modelMatrix, const Matrix4 &viewMatrix, const Matrix4 &projectionMatrix, const Color &color, const std::vector &points, LinesType ltype, float radius) { if (ltype == LinesType::LINES) { for (size_t i=0; iDraw(); // Deactivate the shader program fullscreenShader_.StopProgram(); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } DefaultShader* QuickShapes::default_shader() { return &defaultShader_; } DefaultShader::MaterialProperties* QuickShapes::material() { return &defaultMaterial_; } } // end namespace