+ return str;
+}
+
+string read_version_dependent_file(const string &base, const string &extension)
+{
+ if (movit_shader_model == MOVIT_GLSL_130) {
+ return read_file(base + ".130." + extension);
+ } else if (movit_shader_model == MOVIT_GLSL_150) {
+ return read_file(base + ".150." + extension);
+ } else if (movit_shader_model == MOVIT_ESSL_300) {
+ return read_file(base + ".300es." + extension);
+ } else {
+ assert(false);
+ }
+}
+
+GLuint compile_shader(const string &shader_src, GLenum type)
+{
+ GLuint obj = glCreateShader(type);
+ const GLchar* source[] = { shader_src.data() };
+ const GLint length[] = { (GLint)shader_src.size() };
+ glShaderSource(obj, 1, source, length);
+ glCompileShader(obj);
+
+ GLchar info_log[4096];
+ GLsizei log_length = sizeof(info_log) - 1;
+ glGetShaderInfoLog(obj, log_length, &log_length, info_log);
+ info_log[log_length] = 0;
+ if (strlen(info_log) > 0) {
+ fprintf(stderr, "Shader compile log: %s\n", info_log);
+ }
+
+ GLint status;
+ glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
+ if (status == GL_FALSE) {
+ // Add some line numbers to easier identify compile errors.
+ string src_with_lines = "/* 1 */ ";
+ size_t lineno = 1;
+ for (char ch : shader_src) {
+ src_with_lines.push_back(ch);
+ if (ch == '\n') {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "/* %3zu */ ", ++lineno);
+ src_with_lines += buf;
+ }
+ }
+
+ fprintf(stderr, "Failed to compile shader:\n%s\n", src_with_lines.c_str());
+ exit(1);
+ }
+
+ return obj;
+}
+
+void print_3x3_matrix(const Eigen::Matrix3d& m)
+{
+ printf("%6.4f %6.4f %6.4f\n", m(0,0), m(0,1), m(0,2));
+ printf("%6.4f %6.4f %6.4f\n", m(1,0), m(1,1), m(1,2));
+ printf("%6.4f %6.4f %6.4f\n", m(2,0), m(2,1), m(2,2));
+ printf("\n");
+}
+
+string output_glsl_mat3(const string &name, const Eigen::Matrix3d &m)
+{
+ // Use stringstream to be independent of the current locale in a thread-safe manner.
+ stringstream ss;
+ ss.imbue(locale("C"));
+ ss.precision(8);
+ ss << scientific;
+ ss << "const mat3 " << name << " = mat3(\n";
+ ss << " " << m(0,0) << ", " << m(1,0) << ", " << m(2,0) << ",\n";
+ ss << " " << m(0,1) << ", " << m(1,1) << ", " << m(2,1) << ",\n";
+ ss << " " << m(0,2) << ", " << m(1,2) << ", " << m(2,2) << ");\n\n";
+ return ss.str();
+}
+
+string output_glsl_float(const string &name, float x)
+{
+ // Use stringstream to be independent of the current locale in a thread-safe manner.
+ stringstream ss;
+ ss.imbue(locale("C"));
+ ss.precision(8);
+ ss << scientific;
+ ss << "const float " << name << " = " << x << ";\n";
+ return ss.str();
+}
+
+string output_glsl_vec2(const string &name, float x, float y)
+{
+ // Use stringstream to be independent of the current locale in a thread-safe manner.
+ stringstream ss;
+ ss.imbue(locale("C"));
+ ss.precision(8);
+ ss << scientific;
+ ss << "const vec2 " << name << " = vec2(" << x << ", " << y << ");\n";
+ return ss.str();