+void LocationAllocator::apply(Module &module)
+{
+ for(list<Stage>::iterator i=module.stages.begin(); i!=module.stages.end(); ++i)
+ apply(*i);
+ allocate_locations("uniform");
+}
+
+void LocationAllocator::apply(Stage &stage)
+{
+ swap(used_locations["in"], used_locations["out"]);
+ used_locations["out"].clear();
+
+ stage.content.visit(*this);
+
+ allocate_locations("in");
+ allocate_locations("out");
+}
+
+void LocationAllocator::allocate_locations(const string &iface)
+{
+ vector<VariableDeclaration *>::iterator write = unplaced_variables.begin();
+ unsigned next = 0;
+ for(vector<VariableDeclaration *>::const_iterator i=unplaced_variables.begin(); i!=unplaced_variables.end(); ++i)
+ {
+ if((*i)->interface!=iface)
+ {
+ if(write!=i)
+ *write = *i;
+ ++write;
+ continue;
+ }
+
+ if((*i)->interface=="uniform")
+ {
+ map<string, unsigned>::const_iterator j = uniform_locations.find((*i)->name);
+ if(j!=uniform_locations.end())
+ {
+ add_location((*i)->layout, j->second);
+ continue;
+ }
+ }
+
+ set<unsigned> &used = used_locations[(*i)->interface];
+
+ unsigned size = LocationCounter().apply(**i);
+ while(1)
+ {
+ int blocking = -1;
+ for(unsigned j=0; j<size; ++j)
+ if(used.count(next+j))
+ blocking = next+j;
+ if(blocking<0)
+ break;
+ next = blocking+1;
+ }
+
+ add_location((*i)->layout, next);
+ if((*i)->interface=="uniform")
+ uniform_locations[(*i)->name] = next;
+
+ for(unsigned j=0; j<size; ++j)
+ used.insert(next+j);
+ next += size;
+ }
+
+ unplaced_variables.erase(write, unplaced_variables.end());
+}
+
+void LocationAllocator::add_location(RefPtr<Layout> &layout, unsigned location)
+{
+ if(!layout)
+ layout = new Layout;
+
+ Layout::Qualifier qual;
+ qual.name = "location";
+ qual.has_value = true;
+ qual.value = location;
+ layout->qualifiers.push_back(qual);
+}
+
+void LocationAllocator::visit(VariableDeclaration &var)
+{
+ if(!var.interface.empty() && var.name.compare(0, 3, "gl_"))
+ {
+ int location = (var.layout ? get_layout_value(*var.layout, "location") : -1);
+
+ if(location<0 && var.linked_declaration && var.linked_declaration->layout)
+ {
+ location = get_layout_value(*var.linked_declaration->layout, "location");
+ if(location>=0)
+ add_location(var.layout, location);
+ }
+
+ if(location>=0)
+ {
+ unsigned size = LocationCounter().apply(var);
+ for(unsigned i=0; i<size; ++i)
+ used_locations[var.interface].insert(location+i);
+ if(var.interface=="uniform")
+ uniform_locations[var.name] = location;
+ }
+ else
+ unplaced_variables.push_back(&var);
+ }
+}
+
+