+ switch(type)
+ {
+ case GL_VERTEX_SHADER: { static Require _req(ARB_vertex_shader); } break;
+ case GL_GEOMETRY_SHADER: { static Require _req(ARB_geometry_shader4); } break;
+ case GL_FRAGMENT_SHADER: { static Require _req(ARB_fragment_shader); } break;
+ default: throw invalid_argument("Program::add_stage");
+ }
+
+ unsigned stage_id = glCreateShader(type);
+ stage_ids.push_back(stage_id);
+ glAttachShader(id, stage_id);
+
+ return stage_id;
+}
+
+void Program::add_glsl_stages(const GlslModule &mod, const map<string, int> &spec_values)
+{
+ module = &mod;
+
+ SL::Compiler compiler;
+ compiler.set_source(mod.get_prepared_source(), "<module>");
+ compiler.specialize(spec_values);
+ compiler.compile(SL::Compiler::PROGRAM);
+#ifdef DEBUG
+ string diagnostics = compiler.get_diagnostics();
+ if(!diagnostics.empty())
+ IO::print("Program diagnostics:\n%s\n", diagnostics);
+#endif
+
+ vector<SL::Stage::Type> stages = compiler.get_stages();
+ for(vector<SL::Stage::Type>::const_iterator i=stages.begin(); i!=stages.end(); ++i)
+ {
+ unsigned stage_id = 0;
+ switch(*i)
+ {
+ case SL::Stage::VERTEX: stage_id = add_stage(GL_VERTEX_SHADER); break;
+ case SL::Stage::GEOMETRY: stage_id = add_stage(GL_GEOMETRY_SHADER); break;
+ case SL::Stage::FRAGMENT: stage_id = add_stage(GL_FRAGMENT_SHADER); break;
+ default: throw invalid_operation("Program::add_glsl_stages");
+ }
+
+ string stage_src = compiler.get_stage_glsl(*i);
+ const char *src_ptr = stage_src.data();
+ int src_len = stage_src.size();
+ glShaderSource(stage_id, 1, &src_ptr, &src_len);
+
+ if(*i==SL::Stage::VERTEX)
+ {
+ const map<string, unsigned> &attribs = compiler.get_vertex_attributes();
+ for(map<string, unsigned>::const_iterator j=attribs.begin(); j!=attribs.end(); ++j)
+ glBindAttribLocation(id, j->second, j->first.c_str());
+ }
+
+ if(*i==SL::Stage::FRAGMENT && EXT_gpu_shader4)
+ {
+ const map<string, unsigned> &frag_outs = compiler.get_fragment_outputs();
+ for(map<string, unsigned>::const_iterator j=frag_outs.begin(); j!=frag_outs.end(); ++j)
+ glBindFragDataLocation(id, j->second, j->first.c_str());
+ }
+
+ compile_glsl_stage(stage_id);
+ }
+
+ if(!bindings)
+ bindings = new Bindings;
+ bindings->textures = compiler.get_texture_bindings();
+ bindings->blocks = compiler.get_uniform_block_bindings();
+}
+
+void Program::compile_glsl_stage(unsigned stage_id)
+{
+ glCompileShader(stage_id);
+ bool compiled = get_shader_i(stage_id, GL_COMPILE_STATUS);
+
+ GLsizei info_log_len = get_shader_i(stage_id, GL_INFO_LOG_LENGTH);
+ string info_log(info_log_len+1, 0);
+ glGetShaderInfoLog(stage_id, info_log_len+1, &info_log_len, &info_log[0]);
+ info_log.erase(info_log_len);
+ if(module && module->get_format()==Module::GLSL)
+ info_log = static_cast<const GlslModule *>(module)->get_source_map().translate_errors(info_log);
+
+ if(!compiled)
+ throw compile_error(info_log);
+#ifdef DEBUG
+ if(!info_log.empty())
+ IO::print("Shader compile info log:\n%s", info_log);
+#endif