+
+ unsigned stage_id = glCreateShader(type);
+ stage_ids.push_back(stage_id);
+ glAttachShader(id, stage_id);
+
+ return stage_id;
+}
+
+void Program::add_stages(const Module &mod, const map<string, int> &spec_values)
+{
+ module = &mod;
+
+ SL::Compiler compiler;
+ compiler.set_source(module->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_stage(stage_id);
+ }
+}
+
+void Program::compile_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)
+ info_log = 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
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+void Program::attach_shader(Shader &shader)
+{
+ unsigned shader_id = shader.steal_id();
+ if(!shader_id)
+ throw invalid_argument("Program::attach_shader");
+ stage_ids.push_back(shader_id);
+ compile_stage(shader_id);