// See programCache doc comments to see how caching works here. bool StelQGLGLSLShader::build() { // Unlocked - i.e. not Modified if(state == State_Unlocked && program != NULL) { state = State_Built; return true; } QGLShaderProgram* cached = getProgramFromCache(); // No matching program in cache, need to link a new program. if(cached == NULL) { uintptr_t id = 0; QGLShaderProgram* newProgram = new QGLShaderProgram(renderer->getGLContext()); // Add all the shaders to the program. foreach(QGLShader* shader, defaultVertexShaders) { if(!newProgram->addShader(shader)) {goto FAILED;} id += reinterpret_cast<uintptr_t>(shader); } foreach(OptionalShader shader, namedVertexShaders) { if(shader.enabled) { if(!newProgram->addShader(shader.shader)) {goto FAILED;} id += reinterpret_cast<uintptr_t>(shader.shader); } } foreach(QGLShader* shader, defaultFragmentShaders) { if(!newProgram->addShader(shader)) {goto FAILED;} id += reinterpret_cast<uintptr_t>(shader); } Q_ASSERT_X(id > 0, Q_FUNC_INFO, "Trying to build() a StelQGLGLSLShader " "but no vertex or fragment shaders were added"); // Link the program. if(!newProgram->link()) {goto FAILED;} aggregatedLog += "Built successfully"; // Add the program to the cache, and set the current program to it. programCache.insert(id, newProgram); program = newProgram; state = State_Built; return true; // And here I present to you a viable application of the fabled GOTO statement and a label. // (good way to do error recovery in plan C and when using return codes, BTW) FAILED: aggregatedLog += newProgram->log(); delete newProgram; return false; }
Object *SceneParser::loadObject(KeyValues *data) { const char *format = data->getString("format"); if(!format) { fprintf(stderr, "Key 'format' not found on Object\n"); return NULL; } Mesh *mesh; if(strcmp("OFF", format) == 0 || strcmp("PLY", format) == 0) { const char *file = data->getString("file"); if(!file) { fprintf(stderr, "Key 'file' not found on Object\n"); return NULL; } char *filename = resolvePath(file); MeshData *meshData; if(strcmp("OFF", format) == 0) { meshData = MeshLoaderOFF::load(filename); } else if(strcmp("PLY", format) == 0) { meshData = MeshLoaderPLY::load(filename); } if(!meshData) { fprintf(stderr, "Failed to load MeshData of %s\n", filename); delete[] filename; return NULL; } if(data->getInt("normalize", 1)) { meshData->normalize(); } if(data->getInt("normals", 0)) { meshData->computeNormals(); } const char *texcoords = data->getString("texcoords"); if(texcoords) { MeshData::TexCoordsMethod method; if(strcmp(texcoords, "sphere") == 0) { method = MeshData::TexCoordsSphere; } else if(strcmp(texcoords, "cylinder") == 0) { method = MeshData::TexCoordsCylinder; } meshData->genTexCoords(method); } if(data->getInt("tangents", 0)) { meshData->genTangents(); } mesh = new Mesh(meshData); delete meshData; delete[] filename; } else { fprintf(stderr, "Invalid object format: %s\n", format); return NULL; } Material *material = NULL; QGLShaderProgram *shaderProgram = new QGLShaderProgram(); KeyValues *key; bool error = false; key = data->firstSubKey(); while(key) { if(strcmp(key->name(), "shader") == 0) { QGLShader *shader = loadShader(key); if(shader) { shaderProgram->addShader(shader); } else { fprintf(stderr, "Failed to load shader\n"); error = true; break; } } else if (strcmp(key->name(), "material") == 0) { if(material) { fprintf(stderr, "Duplicated material definition\n"); } else { material = loadMaterial(key); } } key = key->nextKey(); } if(!shaderProgram->link()) { fprintf(stderr, "Failed to link shader program\n"); error = true; } if(error) { if(material) { delete material; } delete shaderProgram; delete mesh; return NULL; } Object *object = new Object(mesh, shaderProgram, material); object->scale(data->getFloat("scale", 1.0)); float pitch = data->getFloat("pitch", 0.0); float yaw = data->getFloat("yaw", 0.0); object->rotation(pitch, yaw); const char *position = data->getString("position"); if(position) { object->position(strtoV3D(position)); } key = data->firstSubKey(); while(key) { if (strcmp(key->name(), "texture") == 0) { Texture *texture = loadTexture(key); if(texture) { object->addTexture(texture); } else { fprintf(stderr, "Failed to load texture\n"); error = true; break; } } key = key->nextKey(); } if(error) { return object; } return object; }
QGLPEXShaderManager::QGLPEXShaderManager(const QGLContext* context) { ctx = const_cast<QGLContext*>(context); defaultVertexShader= new QGLShader(QGLShader::VertexShader, context); defaultVertexShader->addSource(QLatin1String(qglslDefaultVertexShader)); if (!defaultVertexShader->compile()) qWarning() << "Default vertex shader failed to compile: " << defaultVertexShader->log(); noBrushShader = new QGLShader(QGLShader::FragmentShader, context); noBrushShader->addSource(QLatin1String(qglslFragmentShaderMain)); noBrushShader->addSource(QLatin1String(qglslNoBrushFragmentShader)); if (!noBrushShader->compile()) qWarning() << "No brush shader failed to compile:" << noBrushShader->log(); // Create a program for noBrush: QGLShaderProgram* noBrushProg = new QGLShaderProgram(ctx); noBrushProg->addShader(defaultVertexShader); noBrushProg->addShader(noBrushShader); if (!noBrushProg->link()) qWarning() << "NoBrush shader program failed to link:" << noBrushProg->log(); // Add noBrush Program to cache: QGLCachedShaderProg cachedProg; cachedProg.vertexShader = defaultVertexShader; cachedProg.brushShader = noBrushShader; cachedProg.compositionShader = 0; cachedProg.shader = noBrushProg; cachedPrograms.append(cachedProg); // Set state useGlobalOpacity = true; currentBrushStyle = Qt::NoBrush; currentTransformType = FullTransform; shaderProgNeedsChanging = false; activeProgram = noBrushProg; solidBrushShader = 0; conicalBrushVertexShader = 0; conicalBrushFragmentShader = 0; radialBrushVertexShader = 0; radialBrushFragmentShader = 0; linearBrushVertexShader = 0; linearBrushFragmentShader = 0; patternBrushVertexShader = 0; patternBrushFragmentShader = 0; textureBrushFragmentShader = 0; textureBrushVertexShader = 0; simpleFragmentShader = 0; simpleShaderProgram = 0; imageVertexShader = 0; imageFragmentShader = 0; imageShaderProgram = 0; textVertexShader = 0; textFragmentShader = 0; textShaderProgram = 0; }
bool QGLPEXShaderManager::useCorrectShaderProg() { if (!shaderProgNeedsChanging) { activeProgram->use(); return false; } const char* fragmentShaderMainSrc = qglslFragmentShaderMain; QGLShader* vertexShader = defaultVertexShader; QGLShader* fragmentShader = noBrushShader; // Make sure we compile up the correct brush shader switch (currentBrushStyle) { case Qt::NoBrush: break; case Qt::SolidPattern: if (!solidBrushShader) { qDebug("Compiling qglslSolidBrushFragmentShader"); solidBrushShader = new QGLShader(QGLShader::FragmentShader, ctx); solidBrushShader->addSource(QLatin1String(qglslNoOpacityFragmentShaderMain)); solidBrushShader->addSource(QLatin1String(qglslSolidBrushFragmentShader)); if (!solidBrushShader->compile()) qWarning() << "qglslSolidBrush failed to compile:" << solidBrushShader->log(); } fragmentShader = solidBrushShader; break; case Qt::TexturePattern: if (!textureBrushVertexShader) { qDebug("Compiling qglslTextureBrushVertexShader"); textureBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); textureBrushVertexShader->addSource(QLatin1String(qglslTextureBrushVertexShader)); if (!textureBrushVertexShader->compile()) { qWarning() << "qglslTextureBrushVertexShader failed to compile: " << textureBrushVertexShader->log(); } } vertexShader = textureBrushVertexShader; if (!textureBrushFragmentShader) { qDebug("Compiling qglslTextureBrushFragmentShader"); textureBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); textureBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); textureBrushFragmentShader->addSource(QLatin1String(qglslTextureBrushFragmentShader)); if (!textureBrushFragmentShader->compile()) { qWarning() << "qglslTextureBrushFragmentShader failed to compile:" << textureBrushFragmentShader->log(); } } fragmentShader = textureBrushFragmentShader; break; case Qt::LinearGradientPattern: if (!linearBrushVertexShader) { qDebug("Compiling qglslLinearGradientBrushVertexShader"); linearBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); linearBrushVertexShader->addSource(QLatin1String(qglslLinearGradientBrushVertexShader)); if (!linearBrushVertexShader->compile()) { qWarning() << "qglslLinearGradientBrushVertexShader failed to compile: " << linearBrushVertexShader->log(); } } vertexShader = linearBrushVertexShader; if (!linearBrushFragmentShader) { qDebug("Compiling qglslLinearGradientBrushFragmentShader"); linearBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); linearBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); linearBrushFragmentShader->addSource(QLatin1String(qglslLinearGradientBrushFragmentShader)); if (!linearBrushFragmentShader->compile()) { qWarning() << "qglslLinearGradientBrushFragmentShader failed to compile:" << linearBrushFragmentShader->log(); } } fragmentShader = linearBrushFragmentShader; break; case Qt::RadialGradientPattern: if (!radialBrushVertexShader) { qDebug("Compiling qglslRadialGradientBrushVertexShader"); radialBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); radialBrushVertexShader->addSource(QLatin1String(qglslRadialGradientBrushVertexShader)); if (!radialBrushVertexShader->compile()) { qWarning() << "qglslRadialGradientBrushVertexShader failed to compile: " << radialBrushVertexShader->log(); } } vertexShader = radialBrushVertexShader; if (!radialBrushFragmentShader) { qDebug("Compiling qglslRadialGradientBrushFragmentShader"); radialBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); radialBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); radialBrushFragmentShader->addSource(QLatin1String(qglslRadialGradientBrushFragmentShader)); if (!radialBrushFragmentShader->compile()) { qWarning() << "qglslRadialGradientBrushFragmentShader failed to compile:" << radialBrushFragmentShader->log(); } } fragmentShader = radialBrushFragmentShader; break; case Qt::ConicalGradientPattern: // FIXME: We currently use the same vertex shader as radial brush if (!conicalBrushVertexShader) { qDebug("Compiling qglslConicalGradientBrushVertexShader"); conicalBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); conicalBrushVertexShader->addSource(QLatin1String(qglslConicalGradientBrushVertexShader)); if (!conicalBrushVertexShader->compile()) { qWarning() << "qglslConicalGradientBrushVertexShader failed to compile: " << conicalBrushVertexShader->log(); } } vertexShader = conicalBrushVertexShader; if (!conicalBrushFragmentShader) { qDebug("Compiling qglslConicalGradientBrushFragmentShader"); conicalBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); conicalBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); conicalBrushFragmentShader->addSource(QLatin1String(qglslConicalGradientBrushFragmentShader)); if (!conicalBrushFragmentShader->compile()) { qWarning() << "qglslConicalGradientBrushFragmentShader failed to compile:" << conicalBrushFragmentShader->log(); } } fragmentShader = conicalBrushFragmentShader; break; case Qt::Dense1Pattern: case Qt::Dense2Pattern: case Qt::Dense3Pattern: case Qt::Dense4Pattern: case Qt::Dense5Pattern: case Qt::Dense6Pattern: case Qt::Dense7Pattern: case Qt::HorPattern: case Qt::VerPattern: case Qt::CrossPattern: case Qt::BDiagPattern: case Qt::FDiagPattern: case Qt::DiagCrossPattern: if (!patternBrushVertexShader) { qDebug("Compiling qglslPatternBrushVertexShader"); patternBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); patternBrushVertexShader->addSource(QLatin1String(qglslPatternBrushVertexShader)); if (!patternBrushVertexShader->compile()) { qWarning() << "qglslPatternBrushVertexShader failed to compile: " << patternBrushVertexShader->log(); } } vertexShader = patternBrushVertexShader; if (!patternBrushFragmentShader) { qDebug("Compiling qglslPatternBrushFragmentShader"); patternBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); patternBrushFragmentShader->addSource(QLatin1String(qglslNoOpacityFragmentShaderMain)); patternBrushFragmentShader->addSource(QLatin1String(qglslPatternBrushFragmentShader)); if (!patternBrushFragmentShader->compile()) { qWarning() << "qglslPatternBrushFragmentShader failed to compile:" << patternBrushFragmentShader->log(); } } fragmentShader = patternBrushFragmentShader; break; default: qWarning("Unimplemented brush style (%d)", currentBrushStyle); } // Now newBrushShader is set correctly, check to see if we already have the program // already linked and ready to go in the cache: bool foundProgram = false; foreach (QGLCachedShaderProg cachedProg, cachedPrograms) { if ((cachedProg.vertexShader == vertexShader) && (cachedProg.brushShader == fragmentShader) && (cachedProg.compositionShader == 0) ) { activeProgram = cachedProg.shader; foundProgram = true; break; } } if (!foundProgram) { qDebug() << "Linking shader program for " << currentBrushStyle; // Required program not found - create it. QGLShaderProgram* newProg = new QGLShaderProgram(ctx); newProg->addShader(vertexShader); newProg->addShader(fragmentShader); if (!newProg->link()) qWarning() << "Shader program for " << currentBrushStyle << "failed to link:" << newProg->log(); QGLCachedShaderProg cachedProg; cachedProg.vertexShader = vertexShader; cachedProg.brushShader = fragmentShader; cachedProg.compositionShader = 0; cachedProg.shader = newProg; cachedPrograms.append(cachedProg); activeProgram = newProg; } activeProgram->use(); shaderProgNeedsChanging = false; return true; }
void GLWidget::drawPoint(const Vector& pos, float r, float g, float b) { static bool created = false; static QGLShaderProgram program; static GLuint VAO; if (!created) { created = true; // 1. Create shaders QGLShader vs(QGLShader::Vertex); vs.compileSourceCode("#version 330 core \n in vec3 vertex; in vec3 color; uniform mat4 modelViewProjectionMatrix; out vec4 frontColor; void main() { frontColor = vec4(color,1); gl_Position = modelViewProjectionMatrix * vec4(vertex, 1.0); }"); QGLShader fs(QGLShader::Fragment); fs.compileSourceCode("#version 330 core \n in vec4 frontColor; out vec4 FragColor; void main() {FragColor = frontColor;}"); program.addShader(&vs); program.addShader(&fs); program.link(); // Get location of VS attributes GLuint vertexLoc = program.attributeLocation("vertex"); GLuint colorLoc = program.attributeLocation("color"); // 2. Create VBO Buffers // Create & bind empty VAO glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // Create VBO with (x,y,z) coordinates float coords[] = { 0, 0, 0}; GLuint VBO_coords; glGenBuffers(1, &VBO_coords); glBindBuffer(GL_ARRAY_BUFFER, VBO_coords); glBufferData(GL_ARRAY_BUFFER, sizeof(coords), coords, GL_STATIC_DRAW); glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(vertexLoc); // Create VBO with (r,g,b) color float colors[] = {r, g, b}; GLuint VBO_colors; glGenBuffers(1, &VBO_colors); glBindBuffer(GL_ARRAY_BUFFER, VBO_colors); glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); glVertexAttribPointer(colorLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(colorLoc); glBindVertexArray(0); } program.bind(); // 1. Define uniforms QMatrix4x4 T; T.translate(pos); QMatrix4x4 MVP = camera()->projectionMatrix() * camera()->modelviewMatrix()*T; program.setUniformValue("modelViewProjectionMatrix", MVP); // 2. Draw glPointSize(8); glBindVertexArray (VAO); glDrawArrays(GL_POINTS, 0, 1); glBindVertexArray(0); program.release(); }
void GLWidget::drawAxes() { float L = 1; static bool created = false; static QGLShaderProgram program; static GLuint VAO_axes; if (!created) { created = true; // 1. Create shaders // VS QGLShader vs(QGLShader::Vertex); vs.compileSourceCode("#version 330 core \n in vec3 vertex; in vec3 color; uniform mat4 modelViewProjectionMatrix; out vec4 frontColor; void main() { frontColor = vec4(color,1); gl_Position = modelViewProjectionMatrix * vec4(vertex, 1.0); }"); // FS QGLShader fs(QGLShader::Fragment); fs.compileSourceCode("#version 330 core \n in vec4 frontColor; out vec4 FragColor; void main() {FragColor = frontColor;}"); // Program program.addShader(&vs); program.addShader(&fs); program.link(); // Get location of VS attributes GLuint vertexLoc = program.attributeLocation("vertex"); GLuint colorLoc = program.attributeLocation("color"); // 2. Create VBO Buffers // Create & bind empty VAO glGenVertexArrays(1, &VAO_axes); glBindVertexArray(VAO_axes); // Create VBO with (x,y,z) coordinates float coords[] = { 0, 0, 0, L, 0, 0, 0, 0, 0, 0, L, 0, 0, 0, 0, 0, 0, L}; GLuint VBO_coords; glGenBuffers(1, &VBO_coords); glBindBuffer(GL_ARRAY_BUFFER, VBO_coords); glBufferData(GL_ARRAY_BUFFER, sizeof(coords), coords, GL_STATIC_DRAW); glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(vertexLoc); // Create VBO with (r,g,b) color float colors[] = {1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1}; GLuint VBO_colors; glGenBuffers(1, &VBO_colors); glBindBuffer(GL_ARRAY_BUFFER, VBO_colors); glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); glVertexAttribPointer(colorLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(colorLoc); glBindVertexArray(0); } program.bind(); // 1. Define uniforms float r = max(MIN_AXES_LENGTH, scene()->boundingBox().radius()); QMatrix4x4 scale; scale.scale(r,r,r); QMatrix4x4 MVP = camera()->projectionMatrix() * camera()->modelviewMatrix()*scale; program.setUniformValue("modelViewProjectionMatrix", MVP); // 2. Draw glBindVertexArray (VAO_axes); glDrawArrays(GL_LINES, 0, 6); glBindVertexArray(0); program.release(); // 5. CleanUp /* glDeleteVertexArrays(1, &VAO_axes); glDeleteBuffers(1, &VBO_coords); glDeleteBuffers(1, &VBO_colors); */ /* glDisable(GL_LIGHTING); glBegin(GL_LINES); glColor3f(1,0,0); glVertex3f(0,0,0); glVertex3f(L,0,0); // X glColor3f(0,1,0); glVertex3f(0,0,0); glVertex3f(0,L,0); // Y glColor3f(0,0,1); glVertex3f(0,0,0); glVertex3f(0,0,L); // Z glEnd(); glEnable(GL_LIGHTING); */ }