-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path_glprogram.h
More file actions
186 lines (177 loc) · 5.13 KB
/
_glprogram.h
File metadata and controls
186 lines (177 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#pragma once
// _glprogram.h
// Utility object for maintaining lifetime of a glProgram.
// dbien
// 05FEB2022
#include <cstdarg>
#include "glad/glad.h"
#include "bienutil.h"
#include "bien_assert.h"
__BIENUTIL_BEGIN_NAMESPACE
class GLProgram
{
typedef GLProgram _TyThis;
public:
GLProgram() = default;
GLProgram( GLProgram const & ) = delete;
GLProgram & operator=( GLProgram const & ) = delete;
GLProgram( GLProgram && _rr ) noexcept
{
std::swap( m_uProgramId, _rr.m_uProgramId );
}
GLProgram & operator=( GLProgram && _rr ) noexcept
{
GLProgram acquire( std::move( _rr ) );
swap( acquire );
return *this;
}
void swap( _TyThis & _r ) noexcept
{
std::swap( m_uProgramId, _r.m_uProgramId );
}
void AssertValid() const noexcept
{
#if ASSERTSENABLED
// We should either have a null program id or a valid and linked program here.
if ( !m_uProgramId )
return;
GLint iLinkSuccess;
glGetProgramiv( m_uProgramId, GL_LINK_STATUS, &iLinkSuccess );
Assert( !!iLinkSuccess );
// We validate here as a debugging aid - since this only runs in debug:
glValidateProgram( m_uProgramId );
GLint iValidateStatus;
glGetProgramiv( m_uProgramId, GL_VALIDATE_STATUS, &iValidateStatus );
Assert( !!iValidateStatus );
#endif //ASSERTSENABLED
}
// Construct and link the program from a set of shader ids.
// Due to how variable arguments in C++ work must pass the count of shaders first.
GLProgram( bool _fLogErrors, bool _fLogSuccess, size_t _nShaders, GLuint _uShaderId, ... ) noexcept(false)
{
va_list ap;
va_start(ap, _uShaderId);
try
{
(void)_FInit( true, _fLogErrors, _fLogSuccess, _nShaders, _uShaderId, ap );
AssertValid();
}
catch( ... )
{
va_end(ap);
throw;
}
va_end(ap);
}
bool FInit( bool _fThrowOnError, bool _fLogErrors, bool _fLogSuccess, size_t _nShaders, GLuint _uShaderId, ... ) noexcept(false)
{
AssertValid();
Release();
va_list ap;
va_start(ap, _uShaderId);
bool fSuccess;
try
{
fSuccess = _FInit( _fThrowOnError, _fLogErrors, _fLogSuccess, _nShaders, _uShaderId, ap );
}
catch( ... )
{
Assert( _fThrowOnError );
va_end(ap);
throw;
}
va_end(ap);
AssertValid();
return fSuccess;
}
~GLProgram()
{
Release();
}
void Release() noexcept
{
if ( !!m_uProgramId )
{
GLuint uProgramId = m_uProgramId;
m_uProgramId = 0;
glDeleteProgram( uProgramId );
}
}
GLuint UGetProgram() const noexcept
{
return m_uProgramId;
}
void UseProgram() const noexcept
{
glUseProgram( m_uProgramId );
}
void SetInt( const char * _pszUniformName, GLint _i ) noexcept(false)
{
glUniform1i( _IGetUniform( _pszUniformName ), _i );
}
void SetFloat( const char * _pszUniformName, GLfloat _f ) noexcept(false)
{
glUniform1f( _IGetUniform( _pszUniformName ), _f );
}
protected:
GLint _IGetUniform( const char * _pszUniformName ) noexcept(false)
{
GLint iUniform = glGetUniformLocation( m_uProgramId, _pszUniformName );
VerifyThrowSz( -1 != iUniform, "Uniform name [%s] not found.", _pszUniformName );
return iUniform;
}
bool _FInit( bool _fThrowOnError, bool _fLogErrors, bool _fLogSuccess, size_t _nShaders, GLuint _uShaderId, va_list _ap ) noexcept(false)
{
Assert( _nShaders < 4 ); // only three shaders may be connected to a program.
m_uProgramId = glCreateProgram(); // Must delete this before we leave the method if we fail.
if ( _fThrowOnError )
VerifyThrowSz( !!m_uProgramId, "glCreateProgram() failed." );
else
if ( !m_uProgramId )
return false;
glAttachShader( m_uProgramId, _uShaderId );
if ( _nShaders-- > 1 )
{
// Add the remaining shaders:
for ( ; _nShaders--; )
{
GLuint uShaderId = va_arg( _ap, GLuint );
glAttachShader( m_uProgramId, uShaderId );
}
}
glLinkProgram( m_uProgramId );
GLint iLinkSuccess;
glGetProgramiv( m_uProgramId, GL_LINK_STATUS, &iLinkSuccess );
bool fFailed = !iLinkSuccess;
if ( ( fFailed && _fLogErrors ) || _fLogSuccess )
{
GLint nCharsLog;
glGetProgramiv( m_uProgramId, GL_INFO_LOG_LENGTH, &nCharsLog );
if ( nCharsLog || fFailed )
{
// We don't log success if there is no info.
string strLog;
if ( nCharsLog > 1 )
{
strLog.resize( nCharsLog - 1 ); // reserves nCharsLog.
GLsizei nFilled;
glGetProgramInfoLog( m_uProgramId, nCharsLog, &nFilled, &strLog[0] );
Assert( nFilled == ( nCharsLog - 1 ) );
strLog[ nCharsLog - 1 ] = 0; // ensure null termination regardless.
}
const char * pszFmt = strLog.length() ? "InfoLog:%s \"%s\"" : "InfoLog:%s nologinfo";
LOGSYSLOG( fFailed ? eslmtError : eslmtInfo, pszFmt, fFailed ? "FAILED" : "SUCCEEDED", &strLog[0] );
}
}
if ( fFailed )
{
glDeleteProgram( m_uProgramId );
m_uProgramId = 0;
if ( _fThrowOnError )
VerifyThrowSz( !fFailed, "Failed to link program." );
}
return !fFailed;
}
GLuint m_uProgramId{0};
};
__BIENUTIL_END_NAMESPACE