void PointArray::estimateCost(const TransformState& transState, bool incrementalDraw, const double* qualities, DrawCount* drawCounts, int numEstimates) const { TransformState relativeTrans = transState.translate(offset()); V3f relCamera = relativeTrans.cameraPos(); ClipBox clipBox(relativeTrans); std::vector<const OctreeNode*> nodeStack; nodeStack.push_back(m_rootNode.get()); while (!nodeStack.empty()) { const OctreeNode* node = nodeStack.back(); nodeStack.pop_back(); if (clipBox.canCull(node->bbox)) continue; if (!node->isLeaf()) { for (int i = 0; i < 8; ++i) { OctreeNode* n = node->children[i]; if (n) nodeStack.push_back(n); } continue; } for (int i = 0; i < numEstimates; ++i) { drawCounts[i] += node->drawCount(relCamera, qualities[i], incrementalDraw); } } }
void TriMesh::drawEdges(QGLShaderProgram& prog, const TransformState& transState) const { unsigned int vertexShaderId = shaderId("meshedge"); unsigned int vertexArray = getVAO("meshedge"); transState.translate(offset()).setUniforms(vertexShaderId); glBindVertexArray(vertexArray); glDrawElements(GL_LINES, (GLsizei)m_edges.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); }
void Annotation::draw(QGLShaderProgram& annotationShaderProg, const TransformState& transState) const { glBindVertexArray(m_vao); GLint texture0 = glGetUniformLocation(annotationShaderProg.programId(), "texture0"); m_texture->bind(texture0); annotationShaderProg.setUniformValue("annotationSize", m_texture->width(), m_texture->height()); transState.translate(m_position) .setUniforms(annotationShaderProg.programId()); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindTexture(GL_TEXTURE_2D, 0); glBindVertexArray(0); }
void TriMesh::drawEdges(QGLShaderProgram& prog, const TransformState& transState) const { transState.translate(offset()).setUniforms(prog.programId()); prog.enableAttributeArray("position"); prog.setAttributeArray("position", GL_FLOAT, &m_verts[0], 3); if (m_colors.size() == m_verts.size()) { prog.enableAttributeArray("color"); prog.setAttributeArray("color", GL_FLOAT, &m_colors[0], 3); } else prog.setAttributeValue("color", GLfloat(1), GLfloat(1), GLfloat(1)); glDrawElements(GL_LINES, (GLsizei)m_edges.size(), GL_UNSIGNED_INT, &m_edges[0]); prog.disableAttributeArray("color"); prog.disableAttributeArray("position"); }
void TriMesh::drawFaces(QGLShaderProgram& prog, const TransformState& transState) const { // TODO: The hasTexture uniform shader variable would be unnecessary if we // supported more than one mesh face shader... GLint hasTextureLoc = glGetUniformLocation(prog.programId(), "hasTexture"); if (m_texture) { GLint textureSamplerLoc = glGetUniformLocation(prog.programId(), "texture0"); if (textureSamplerLoc != -1) m_texture->bind(textureSamplerLoc); } if (hasTextureLoc != -1) glUniform1i(hasTextureLoc, m_texture ? 1 : 0); unsigned int vertexShaderId = shaderId("meshface"); unsigned int vertexArray = getVAO("meshface"); transState.translate(offset()).setUniforms(vertexShaderId); glBindVertexArray(vertexArray); glDrawElements(GL_TRIANGLES, (GLsizei)m_triangles.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); }
DrawCount PointArray::drawPoints(QGLShaderProgram& prog, const TransformState& transState, double quality, bool incrementalDraw) const { TransformState relativeTrans = transState.translate(offset()); relativeTrans.setUniforms(prog.programId()); //printActiveShaderAttributes(prog.programId()); std::vector<ShaderAttribute> activeAttrs = activeShaderAttributes(prog.programId()); // Figure out shader locations for each point field // TODO: attributeLocation() forces the OpenGL usage here to be // synchronous. Does this matter? (Alternative: bind them ourselves.) std::vector<const ShaderAttribute*> attributes; for (size_t i = 0; i < m_fields.size(); ++i) { const GeomField& field = m_fields[i]; if (field.spec.isArray()) { for (int j = 0; j < field.spec.count; ++j) { std::string name = tfm::format("%s[%d]", field.name, j); attributes.push_back(findAttr(name, activeAttrs)); } } else { attributes.push_back(findAttr(field.name, activeAttrs)); } } // Zero out active attributes in case they don't have associated fields GLfloat zeros[16] = {0}; for (size_t i = 0; i < activeAttrs.size(); ++i) { prog.setAttributeValue((int)i, zeros, activeAttrs[i].rows, activeAttrs[i].cols); } // Enable attributes which have associated fields for (size_t i = 0; i < attributes.size(); ++i) { if (attributes[i]) prog.enableAttributeArray(attributes[i]->location); } DrawCount drawCount; ClipBox clipBox(relativeTrans); // Draw points in each bucket, with total number drawn depending on how far // away the bucket is. Since the points are shuffled, this corresponds to // a stochastic simplification of the full point cloud. V3f relCamera = relativeTrans.cameraPos(); std::vector<const OctreeNode*> nodeStack; nodeStack.push_back(m_rootNode.get()); while (!nodeStack.empty()) { const OctreeNode* node = nodeStack.back(); nodeStack.pop_back(); if (clipBox.canCull(node->bbox)) continue; if (!node->isLeaf()) { for (int i = 0; i < 8; ++i) { OctreeNode* n = node->children[i]; if (n) nodeStack.push_back(n); } continue; } size_t idx = node->beginIndex; if (!incrementalDraw) node->nextBeginIndex = node->beginIndex; DrawCount nodeDrawCount = node->drawCount(relCamera, quality, incrementalDraw); drawCount += nodeDrawCount; idx = node->nextBeginIndex; if (nodeDrawCount.numVertices == 0) continue; for (size_t i = 0, k = 0; i < m_fields.size(); k+=m_fields[i].spec.arraySize(), ++i) { const GeomField& field = m_fields[i]; int arraySize = field.spec.arraySize(); int vecSize = field.spec.vectorSize(); for (int j = 0; j < arraySize; ++j) { const ShaderAttribute* attr = attributes[k+j]; if (!attr) continue; char* data = field.data.get() + idx*field.spec.size() + j*field.spec.elsize; if (attr->baseType == TypeSpec::Int || attr->baseType == TypeSpec::Uint) { glVertexAttribIPointer(attr->location, vecSize, glBaseType(field.spec), 0, data); } else { glVertexAttribPointer(attr->location, vecSize, glBaseType(field.spec), field.spec.fixedPoint, 0, data); } } } glDrawArrays(GL_POINTS, 0, (GLsizei)nodeDrawCount.numVertices); node->nextBeginIndex += nodeDrawCount.numVertices; } //tfm::printf("Drew %d of total points %d, quality %f\n", totDraw, m_npoints, quality); // Disable all attribute arrays - leaving these enabled seems to screw with // the OpenGL fixed function pipeline in unusual ways. for (size_t i = 0; i < attributes.size(); ++i) { if (attributes[i]) prog.disableAttributeArray(attributes[i]->location); } return drawCount; }
/// Draw the 3D cursor void View3D::drawCursor(const TransformState& transStateIn, const V3d& cursorPos, float centerPointRadius) const { V3d offset = transStateIn.cameraPos(); TransformState transState = transStateIn.translate(offset); V3d relCursor = cursorPos - offset; // Cull if behind camera if((relCursor * transState.modelViewMatrix).z > 0) return; // Find position of cursor in screen space V3d screenP3 = relCursor * transState.modelViewMatrix * transState.projMatrix; // Position in ortho coord system V2f p2 = 0.5f * V2f(width(), height()) * (V2f(screenP3.x, screenP3.y) + V2f(1.0f)); // Draw cursor if (m_cursorShader->isValid()) { QGLShaderProgram& cursorShader = m_cursorShader->shaderProgram(); // shader cursorShader.bind(); // vertex array glBindVertexArray(m_cursorVertexArray); transState.projMatrix.makeIdentity(); transState.setOrthoProjection(0, width(), 0, height(), 0, 1); transState.modelViewMatrix.makeIdentity(); if (centerPointRadius > 0) { // fake drawing of white point through scaling ... // TransformState pointState = transState.translate( V3d(p2.x, p2.y, 0) ); pointState = pointState.scale( V3d(0.0,0.0,0.0) ); glLineWidth(centerPointRadius); cursorShader.setUniformValue("color", 1.0f, 1.0f, 1.0f, 1.0f); pointState.setUniforms(cursorShader.programId()); glDrawArrays( GL_POINTS, 0, 1 ); } // Now draw a 2D overlay over the 3D scene to allow user to pinpoint the // cursor, even when when it's behind something. glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); glLineWidth(1); // this won't work anymore for values larger than 1 (2.0f); // draw white lines transState = transState.translate( V3d(p2.x, p2.y, 0) ); cursorShader.setUniformValue("color", 1.0f, 1.0f, 1.0f, 1.0f); transState.setUniforms(cursorShader.programId()); glDrawArrays( GL_LINES, 0, 8 ); // draw black lines transState = transState.rotate( V4d(0,0,1,0.785398) ); //45 deg cursorShader.setUniformValue("color", 0.0f, 0.0f, 0.0f, 1.0f); transState.setUniforms(cursorShader.programId()); glDrawArrays( GL_LINES, 0, 8 ); } }
DrawCount PointArray::drawPoints(QGLShaderProgram& prog, const TransformState& transState, double quality, bool incrementalDraw) const { GLuint vao = getVAO("points"); glBindVertexArray(vao); GLuint vbo = getVBO("point_buffer"); glBindBuffer(GL_ARRAY_BUFFER, vbo); TransformState relativeTrans = transState.translate(offset()); relativeTrans.setUniforms(prog.programId()); //printActiveShaderAttributes(prog.programId()); std::vector<ShaderAttribute> activeAttrs = activeShaderAttributes(prog.programId()); // Figure out shader locations for each point field // TODO: attributeLocation() forces the OpenGL usage here to be // synchronous. Does this matter? (Alternative: bind them ourselves.) std::vector<const ShaderAttribute*> attributes; for (size_t i = 0; i < m_fields.size(); ++i) { const GeomField& field = m_fields[i]; if (field.spec.isArray()) { for (int j = 0; j < field.spec.count; ++j) { std::string name = tfm::format("%s[%d]", field.name, j); attributes.push_back(findAttr(name, activeAttrs)); } } else { attributes.push_back(findAttr(field.name, activeAttrs)); } } // Zero out active attributes in case they don't have associated fields GLfloat zeros[16] = {0}; for (size_t i = 0; i < activeAttrs.size(); ++i) { prog.setAttributeValue((int)i, zeros, activeAttrs[i].rows, activeAttrs[i].cols); } // Enable attributes which have associated fields for (size_t i = 0; i < attributes.size(); ++i) { if (attributes[i]) prog.enableAttributeArray(attributes[i]->location); } DrawCount drawCount; ClipBox clipBox(relativeTrans); // Draw points in each bucket, with total number drawn depending on how far // away the bucket is. Since the points are shuffled, this corresponds to // a stochastic simplification of the full point cloud. V3f relCamera = relativeTrans.cameraPos(); std::vector<const OctreeNode*> nodeStack; nodeStack.push_back(m_rootNode.get()); while (!nodeStack.empty()) { const OctreeNode* node = nodeStack.back(); nodeStack.pop_back(); if (clipBox.canCull(node->bbox)) continue; if (!node->isLeaf()) { for (int i = 0; i < 8; ++i) { OctreeNode* n = node->children[i]; if (n) nodeStack.push_back(n); } continue; } size_t idx = node->beginIndex; if (!incrementalDraw) node->nextBeginIndex = node->beginIndex; DrawCount nodeDrawCount = node->drawCount(relCamera, quality, incrementalDraw); drawCount += nodeDrawCount; idx = node->nextBeginIndex; if (nodeDrawCount.numVertices == 0) continue; if (m_fields.size() < 1) continue; long bufferSize = 0; for (size_t i = 0; i < m_fields.size(); ++i) { const GeomField &field = m_fields[i]; unsigned int arraySize = field.spec.arraySize(); unsigned int vecSize = field.spec.vectorSize(); // tfm::printfln("FIELD-NAME: %s", field.name); // tfm::printfln("AS: %i, VS: %i, FSS: %i, FSES: %i, GLBTFSS: %i", arraySize, vecSize, field.spec.size(), field.spec.elsize, sizeof(glBaseType(field.spec))); bufferSize += arraySize * vecSize * field.spec.elsize; //sizeof(glBaseType(field.spec)); } bufferSize = bufferSize * (GLsizei)nodeDrawCount.numVertices; // TODO: might be able to do something more efficient here, for example use glBufferSubData to avoid re-allocation of memory by glBufferData // INITIALIZE THE BUFFER TO FULL SIZE // tfm::printfln("INIT BUFFER: %i, BS: %i", vbo, bufferSize); glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)bufferSize, NULL, GL_STREAM_DRAW); /// ======================================================================== /// ======================================================================== GLintptr bufferOffset = 0; for (size_t i = 0, k = 0; i < m_fields.size(); k+=m_fields[i].spec.arraySize(), ++i) { const GeomField& field = m_fields[i]; int arraySize = field.spec.arraySize(); int vecSize = field.spec.vectorSize(); // TODO: should use a single data-array that isn't split into vertex / normal / color / etc. sections, but has interleaved data ? // OpenGL has a stride value in glVertexAttribPointer for exactly this purpose, which should be used for better efficiency // here we write only the current attribute data into this the buffer (e.g. all positions, then all colors) bufferSize = arraySize * vecSize * field.spec.elsize * (GLsizei)nodeDrawCount.numVertices; //sizeof(glBaseType(field.spec)) char* bufferData = field.data.get() + idx*field.spec.size(); glBufferSubData(GL_ARRAY_BUFFER, bufferOffset, bufferSize, bufferData); // tfm::printfln("UPDATE BUFFER: %i, BS: %i", vbo, bufferSize); for (int j = 0; j < arraySize; ++j) { const ShaderAttribute* attr = attributes[k+j]; if (!attr) continue; // we have to create an intermediate buffer offsets for glVertexAttribPointer, but we can still upload the whole data array earlier !? GLintptr intermediate_bufferOffset = bufferOffset + j*field.spec.elsize; if (attr->baseType == TypeSpec::Int || attr->baseType == TypeSpec::Uint) { glVertexAttribIPointer(attr->location, vecSize, glBaseType(field.spec), 0, (const GLvoid *)intermediate_bufferOffset); } else { glVertexAttribPointer(attr->location, vecSize, glBaseType(field.spec), field.spec.fixedPoint, 0, (const GLvoid *)intermediate_bufferOffset); } glEnableVertexAttribArray(attr->location); } bufferOffset += bufferSize; } glDrawArrays(GL_POINTS, 0, (GLsizei)nodeDrawCount.numVertices); node->nextBeginIndex += nodeDrawCount.numVertices; } //tfm::printf("Drew %d of total points %d, quality %f\n", totDraw, m_npoints, quality); // Disable all attribute arrays - leaving these enabled seems to screw with // the OpenGL fixed function pipeline in unusual ways. for (size_t i = 0; i < attributes.size(); ++i) { if (attributes[i]) prog.disableAttributeArray(attributes[i]->location); } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); return drawCount; }