• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 18040375504

26 Sep 2025 02:15PM UTC coverage: 69.77% (+1.2%) from 68.577%
18040375504

push

github

paulmthompson
line selection works across widgets

5 of 20 new or added lines in 3 files covered. (25.0%)

463 existing lines in 11 files now uncovered.

42945 of 61552 relevant lines covered (69.77%)

1128.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.74
/src/WhiskerToolbox/ShaderManager/ShaderProgram.cpp
1
#include "ShaderProgram.hpp"
2

3
#include <QDebug>
4
#include <QFile>
5
#include <QOpenGLContext>
6
#include <QOpenGLShader>
7
#include <QTextStream>
8

9
#include <iostream>
10

11
ShaderProgram::ShaderProgram(std::string const & vertexPath,
190✔
12
                             std::string const & fragmentPath,
13
                             std::string const & geometryPath,
14
                             ShaderSourceType sourceType)
190✔
15
    : m_vertexPath(vertexPath),
190✔
16
      m_fragmentPath(fragmentPath),
190✔
17
      m_geometryPath(geometryPath),
190✔
18
      m_sourceType(sourceType),
190✔
19
      m_isComputeShader(false) {
380✔
20
    m_program = std::make_unique<QOpenGLShaderProgram>();
190✔
21
}
190✔
22

23
ShaderProgram::ShaderProgram(std::string const & computePath,
3✔
24
                             ShaderSourceType sourceType)
3✔
25
    : m_computePath(computePath),
3✔
26
      m_sourceType(sourceType),
3✔
27
      m_isComputeShader(true) {
6✔
28
    m_program = std::make_unique<QOpenGLShaderProgram>();
3✔
29
}
3✔
30

31
ShaderProgram::~ShaderProgram() {
193✔
32
    // Don't explicitly call removeAllShaders() in destructor
33
    // QOpenGLShaderProgram's destructor will handle OpenGL resource cleanup
34
    // when the context is still valid, and skip it when the context is gone
35
}
193✔
36

37
bool ShaderProgram::reload() {
193✔
38
    // Save old program in case reload fails
39
    auto oldProgram = std::move(m_program);
193✔
40
    m_program = std::make_unique<QOpenGLShaderProgram>();
193✔
41
    bool const success = compileAndLink();
193✔
42
    if (!success) {
193✔
UNCOV
43
        m_program = std::move(oldProgram);
×
44
        return false;
×
45
    }
46
    m_uniformLocations.clear();
193✔
47
    return true;
193✔
48
}
193✔
49

50
void ShaderProgram::use() {
×
UNCOV
51
    if (m_program) {
×
52
        m_program->bind();
×
53
    }
54
}
×
55

56
void ShaderProgram::setUniform(std::string const & name, int value) {
×
UNCOV
57
    if (m_program) {
×
58
        m_program->setUniformValue(name.c_str(), value);
×
59
    }
60
}
×
61

62
void ShaderProgram::setUniform(std::string const & name, float value) {
×
UNCOV
63
    if (m_program) {
×
UNCOV
64
        m_program->setUniformValue(name.c_str(), value);
×
65
    }
UNCOV
66
}
×
67

UNCOV
68
void ShaderProgram::setUniform(std::string const & name, glm::mat4 const & matrix) {
×
UNCOV
69
    if (m_program) {
×
UNCOV
70
        m_program->setUniformValue(name.c_str(), QMatrix4x4(&matrix[0][0]));
×
71
    }
UNCOV
72
}
×
73

74
bool ShaderProgram::compileAndLink() {
193✔
75
    bool ok = true;
193✔
76
    QString errorLog;
193✔
77
    
78
    // Handle compute shaders differently
79
    if (m_isComputeShader) {
193✔
80
        if (!m_computePath.empty()) {
3✔
81
            QString src;
3✔
82
            if (m_sourceType == ShaderSourceType::FileSystem) {
3✔
UNCOV
83
                std::string source;
×
UNCOV
84
                if (!loadShaderSource(m_computePath, source)) {
×
UNCOV
85
                    std::cerr << "[ShaderProgram] Failed to load compute shader: " << m_computePath << std::endl;
×
UNCOV
86
                    return false;
×
87
                } else {
88
                    src = QString::fromStdString(source);
×
89
                }
UNCOV
90
            } else {
×
91
                std::string source;
3✔
92
                if (!loadShaderSourceResource(m_computePath, source)) {
3✔
UNCOV
93
                    std::cerr << "[ShaderProgram] Failed to load compute shader resource: " << m_computePath << std::endl;
×
UNCOV
94
                    return false;
×
95
                } else {
96
                    src = QString::fromStdString(source);
3✔
97
                }
98
            }
3✔
99
            if (!m_program->addShaderFromSourceCode(QOpenGLShader::Compute, src)) {
3✔
UNCOV
100
                errorLog += m_program->log();
×
UNCOV
101
                std::cerr << "[ShaderProgram] Compute shader compile error: " << errorLog.toStdString() << std::endl;
×
UNCOV
102
                return false;
×
103
            }
104
        }
3✔
105
    } else {
106
        // Traditional vertex/fragment/geometry shaders
107
        // Vertex shader
108
        if (!m_vertexPath.empty()) {
190✔
109
        QString src;
190✔
110
        if (m_sourceType == ShaderSourceType::FileSystem) {
190✔
111
            std::string source;
2✔
112
            if (!loadShaderSource(m_vertexPath, source)) {
2✔
113
                std::cerr << "[ShaderProgram] Failed to load vertex shader: " << m_vertexPath << std::endl;
×
114
                ok = false;
×
115
            } else {
116
                src = QString::fromStdString(source);
2✔
117
            }
118
        } else {
2✔
119
            std::string source;
188✔
120
            if (!loadShaderSourceResource(m_vertexPath, source)) {
188✔
121
                std::cerr << "[ShaderProgram] Failed to load vertex shader resource: " << m_vertexPath << std::endl;
×
122
                ok = false;
×
123
            } else {
124
                src = QString::fromStdString(source);
188✔
125
            }
126
        }
188✔
127
        if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, src)) {
190✔
128
            errorLog += m_program->log();
×
UNCOV
129
            ok = false;
×
130
        }
131
    }
190✔
132
    // Fragment shader
133
    if (!m_fragmentPath.empty()) {
190✔
134
        QString src;
190✔
135
        if (m_sourceType == ShaderSourceType::FileSystem) {
190✔
136
            std::string source;
2✔
137
            if (!loadShaderSource(m_fragmentPath, source)) {
2✔
138
                std::cerr << "[ShaderProgram] Failed to load fragment shader: " << m_fragmentPath << std::endl;
×
139
                ok = false;
×
140
            } else {
141
                src = QString::fromStdString(source);
2✔
142
            }
143
        } else {
2✔
144
            std::string source;
188✔
145
            if (!loadShaderSourceResource(m_fragmentPath, source)) {
188✔
UNCOV
146
                std::cerr << "[ShaderProgram] Failed to load fragment shader resource: " << m_fragmentPath << std::endl;
×
147
                ok = false;
×
148
            } else {
149
                src = QString::fromStdString(source);
188✔
150
            }
151
        }
188✔
152
        if (!m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, src)) {
190✔
UNCOV
153
            errorLog += m_program->log();
×
UNCOV
154
            ok = false;
×
155
        }
156
    }
190✔
157
    // Geometry shader (optional)
158
    if (!m_geometryPath.empty()) {
190✔
159
        QString src;
35✔
160
        if (m_sourceType == ShaderSourceType::FileSystem) {
35✔
UNCOV
161
            std::string source;
×
UNCOV
162
            if (!loadShaderSource(m_geometryPath, source)) {
×
UNCOV
163
                std::cerr << "[ShaderProgram] Failed to load geometry shader: " << m_geometryPath << std::endl;
×
UNCOV
164
                ok = false;
×
165
            } else {
166
                src = QString::fromStdString(source);
×
167
            }
UNCOV
168
        } else {
×
169
            std::string source;
35✔
170
            if (!loadShaderSourceResource(m_geometryPath, source)) {
35✔
UNCOV
171
                std::cerr << "[ShaderProgram] Failed to load geometry shader resource: " << m_geometryPath << std::endl;
×
UNCOV
172
                ok = false;
×
173
            } else {
174
                src = QString::fromStdString(source);
35✔
175
            }
176
        }
35✔
177
        if (!m_program->addShaderFromSourceCode(QOpenGLShader::Geometry, src)) {
35✔
UNCOV
178
            errorLog += m_program->log();
×
UNCOV
179
            ok = false;
×
180
        }
181
    }
35✔
182
    }  // End of else block for traditional shaders
183
    if (!ok) {
193✔
UNCOV
184
        std::cerr << "[ShaderProgram] Shader compile/link error: " << errorLog.toStdString() << std::endl;
×
UNCOV
185
        return false;
×
186
    }
187
    if (!m_program->link()) {
193✔
UNCOV
188
        std::cerr << "[ShaderProgram] Program link error: " << m_program->log().toStdString() << std::endl;
×
UNCOV
189
        return false;
×
190
    }
191
    return true;
193✔
192
}
193✔
193

194
bool ShaderProgram::loadShaderSource(std::string const & path, std::string & outSource) const {
4✔
195
    QFile file(QString::fromStdString(path));
4✔
196
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
4✔
UNCOV
197
        return false;
×
198
    }
199
    QTextStream in(&file);
4✔
200
    outSource = in.readAll().toStdString();
4✔
201
    return true;
4✔
202
}
4✔
203

204
bool ShaderProgram::loadShaderSourceResource(std::string const & resourcePath, std::string & outSource) const {
414✔
205
    QFile file(QString::fromStdString(resourcePath));
414✔
206
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
414✔
UNCOV
207
        return false;
×
208
    }
209
    QTextStream in(&file);
414✔
210
    outSource = in.readAll().toStdString();
414✔
211
    return true;
414✔
212
}
414✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc