19 std::string fragmentShader,
20 std::unordered_map<int, std::string> inAttributes,
23 attrib_idx = inAttributes;
24 num_outputs = numOutputs;
28 std::string fmtVS = formatShader(vertexShader, GL_VERTEX_SHADER);
29 vertex_shader = compileShader(fmtVS, GL_VERTEX_SHADER);
30 if (vertex_shader == 0)
35 std::string fmtFS = formatShader(fragmentShader, GL_FRAGMENT_SHADER);
36 fragment_shader = compileShader(fmtFS, GL_FRAGMENT_SHADER);
37 if (fragment_shader == 0)
42 if (!linkShaders({vertex_shader, fragment_shader}))
44 std::cerr <<
"Failed to link shaders for program." << std::endl;
54 int ShaderProgram::glsl_version = -1;
55 #ifndef __EMSCRIPTEN__
56 const bool ShaderProgram::glsl_is_es =
false;
58 const bool ShaderProgram::glsl_is_es =
true;
61 void ShaderProgram::GetGLSLVersion()
63 if (glsl_version == -1)
65 std::string verStr = (
char*)glGetString(GL_VERSION);
66 int ver_major, ver_minor;
67 int vs_idx = verStr.find_first_of(
".");
68 ver_major = std::stoi(verStr.substr(vs_idx - 1, vs_idx));
69 ver_minor = std::stoi(verStr.substr(vs_idx + 1, 1));
70 int opengl_ver = ver_major * 100 + ver_minor * 10;
72 #ifndef __EMSCRIPTEN__
88 glsl_version = opengl_ver - 90;
90 else if (ver_major == 3)
92 glsl_version = opengl_ver - 170;
96 std::cerr <<
"fatal: unsupported OpenGL version " << opengl_ver << std::endl;
102 glsl_version = opengl_ver;
109 if (opengl_ver < 300)
118 std::cerr <<
"Using GLSL " << glsl_version;
119 if (glsl_is_es) { std::cerr <<
" ES"; }
120 std::cerr << std::endl;
124 std::string ShaderProgram::formatShader(
const std::string& inShader,
127 std::string formatted = inShader;
130 if (glsl_version >= 130)
132 if (shaderType == GL_VERTEX_SHADER)
134 formatted = std::regex_replace(formatted, std::regex(
"attribute"),
"in");
135 formatted = std::regex_replace(formatted, std::regex(
"varying"),
"out");
137 else if (shaderType == GL_FRAGMENT_SHADER)
139 formatted = std::regex_replace(formatted, std::regex(
"varying"),
"in");
140 for (
int i = 0; i < num_outputs; i++)
142 std::string indexString =
"gl_FragData[";
143 indexString += std::to_string(i) +
"]";
144 std::string outputString =
"out vec4 fragColor_";
145 outputString += std::to_string(i) +
";\n";
146 if (glsl_version >= 300)
150 std::string layoutString =
"layout(location = ";
151 layoutString += std::to_string(i) +
") ";
152 formatted = layoutString + outputString + formatted;
159 formatted = outputString + formatted;
161 std::string indexStringRgx =
"gl_FragData\\[";
162 indexStringRgx += std::to_string(i) +
"\\]";
163 formatted = std::regex_replace(formatted, std::regex(indexStringRgx),
164 "fragColor_" + std::to_string(i));
167 formatted = std::regex_replace(formatted, std::regex(
"gl_FragColor"),
174 std::cerr <<
"buildShaderString: unknown shader type" << std::endl;
178 formatted = std::regex_replace(formatted, std::regex(
"texture2D"),
"texture");
183 formatted =
"#define USE_ALPHA\n" + formatted;
188 if (shaderType == GL_FRAGMENT_SHADER)
191 formatted =
"precision mediump float;\n" + formatted;
193 if (num_outputs > 1 && glsl_version == 100)
196 formatted =
"#extension GL_EXT_draw_buffers : require\n" + formatted;
198 if (glsl_version == 300)
201 formatted =
"#version 300 es\n" + formatted;
207 formatted = std::regex_replace(
"#version GLSL_VER\n", std::regex(
"GLSL_VER"),
208 std::to_string(glsl_version)) + formatted;
214 GLuint ShaderProgram::compileShader(
const std::string& inShader,
217 int shader_len = inShader.length();
218 const char *shader_cstr = inShader.c_str();
220 GLuint shader = glCreateShader(shaderType);
221 glShaderSource(shader, 1, &shader_cstr, &shader_len);
222 glCompileShader(shader);
225 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
227 if (stat == GL_FALSE)
229 std::cerr <<
"failed to compile shader" << std::endl;
231 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &err_len);
232 char *error_text =
new char[err_len];
233 glGetShaderInfoLog(shader, err_len, &err_len, error_text);
234 std::cerr << error_text << std::endl;
241 bool ShaderProgram::linkShaders(
const std::vector<GLuint>& shaders)
244 for (
auto attrib_pair : attrib_idx)
246 glBindAttribLocation(program_id, attrib_pair.first,
247 attrib_pair.second.c_str());
250 #ifndef __EMSCRIPTEN__
251 if (glsl_version >= 130 && glsl_version < 300)
254 for (
int i = 0; i < num_outputs; i++)
256 std::string fragOutVar =
"fragColor_" + std::to_string(i);
257 glBindFragDataLocation(program_id, i, fragOutVar.c_str());
262 for (GLuint i : shaders)
264 glAttachShader(program_id, i);
266 glLinkProgram(program_id);
269 glGetProgramiv(program_id, GL_LINK_STATUS, &stat);
270 if (stat == GL_FALSE)
272 cerr <<
"fatal: Shader linking failed" << endl;
274 return (stat == GL_TRUE);
277 void ShaderProgram::mapShaderUniforms()
280 glGetProgramiv(program_id, GL_ACTIVE_UNIFORMS, &num_unifs);
282 glGetProgramiv(program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_unif_len);
284 for (
int i = 0; i < num_unifs; i++)
286 vector<char> unif_buf(max_unif_len+1);
290 glGetActiveUniform(program_id, i, max_unif_len, &name_length, &gl_size,
293 std::string unif_name(unif_buf.data(), name_length);
294 GLuint location = glGetUniformLocation(program_id, unif_name.c_str());
295 uniform_idx[unif_name] = location;
bool create(std::string vertexShader, std::string fragmentShader, std::unordered_map< int, std::string > inAttributes, int numOutputs)
static bool useLegacyTextureFmts()