/*
* This file is part of the Haven & Hearth game client.
* Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and
* Björn Johannessen <johannessen.bjorn@gmail.com>
*
* Redistribution and/or modification of this file is subject to the
* terms of the GNU Lesser General Public License, version 3, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Other parts of this source tree adhere to other copying
* rights. Please see the file `COPYING' in the root directory of the
* source tree for details.
*
* A copy the GNU Lesser General Public License is distributed along
* with the source tree of which this file is a part in the file
* `doc/LPGL-3'. If it is missing for any reason, please see the Free
* Software Foundation's website at <http://www.fsf.org/>, or write
* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package haven.glsl;
import haven.*;
import java.util.*;
import java.io.*;
import haven.GLShader.VertexShader;
import haven.GLShader.FragmentShader;
public interface ShaderMacro {
public void modify(ProgramContext prog);
public static class Program extends GLProgram {
public static boolean dumpall = false;
public transient final ProgramContext built;
private final transient int[][] automask;
private final transient Uniform.AutoApply[] auto;
private final transient boolean[] adirty;
private transient int[] autolocs;
private static Collection<GLShader> build(ProgramContext prog) {
Collection<GLShader> ret = new LinkedList<GLShader>();
StringWriter fbuf = new StringWriter();
prog.fctx.construct(fbuf);
ret.add(new FragmentShader(fbuf.toString()));
StringWriter vbuf = new StringWriter();
prog.vctx.construct(vbuf);
ret.add(new VertexShader(vbuf.toString()));
return(ret);
}
@SuppressWarnings("unchecked")
public Program(ProgramContext ctx) {
super(build(ctx));
this.built = ctx;
{
List<Uniform.AutoApply> auto = new LinkedList<Uniform.AutoApply>();
for(Uniform var : ctx.uniforms) {
if(var instanceof Uniform.AutoApply)
auto.add((Uniform.AutoApply)var);
}
this.auto = auto.toArray(new Uniform.AutoApply[0]);
}
this.adirty = new boolean[this.auto.length];
{
int max = -1;
for(Uniform.AutoApply auto : this.auto) {
for(GLState.Slot slot : auto.deps)
max = Math.max(max, slot.id);
}
LinkedList<Integer>[] buf = (LinkedList<Integer>[])new LinkedList[max + 1];
for(int i = 0; i < auto.length; i++) {
for(GLState.Slot slot : auto[i].deps) {
if(buf[slot.id] == null)
buf[slot.id] = new LinkedList<Integer>();
buf[slot.id].add(i);
}
}
automask = new int[max + 1][];
for(int i = 0; i <= max; i++) {
if(buf[i] == null) {
automask[i] = new int[0];
} else {
automask[i] = new int[buf[i].size()];
int o = 0;
for(int s : buf[i])
automask[i][o++] = s;
}
}
}
}
public void adirty(GLState.Slot slot) {
if(slot.id < automask.length) {
for(int i : automask[slot.id])
adirty[i] = true;
}
}
public void autoapply(GOut g, boolean all) {
if(autolocs == null) {
autolocs = new int[auto.length];
for(int i = 0; i < auto.length; i++)
autolocs[i] = uniform(auto[i]);
}
for(int i = 0; i < auto.length; i++) {
if(all || adirty[i])
auto[i].apply(g, autolocs[i]);
adirty[i] = false;
}
}
public static Program build(Collection<ShaderMacro> mods) {
ProgramContext prog = new ProgramContext();
for(ShaderMacro mod : mods)
mod.modify(prog);
Program ret = new Program(prog);
if(dumpall || prog.dump) {
System.err.println(mods + ": ");
for(GLShader sh : ret.shaders) {
System.err.println("---> " + sh + ": ");
System.err.print(sh.source);
}
System.err.println();
System.err.println("-------- " + ret);
System.err.println();
}
return(ret);
}
public void dispose() {
synchronized(this) {
super.dispose();
umap.clear();
amap.clear();
}
}
/* XXX: It would be terribly nice to replace these with some faster operation. */
private final Map<Uniform, Integer> umap = new IdentityHashMap<Uniform, Integer>();
public int cuniform(Uniform var) {
Integer r = umap.get(var);
if(r == null) {
String nm = built.symtab.get(var.name);
if(nm == null)
r = new Integer(-1);
else
r = new Integer(uniform(nm));
umap.put(var, r);
}
return(r.intValue());
}
public int uniform(Uniform var) {
int r = cuniform(var);
if(r < 0)
throw(new ProgramException("Uniform not found in symtab: " + var, this, null));
return(r);
}
private final Map<Attribute, Integer> amap = new IdentityHashMap<Attribute, Integer>();
public int cattrib(Attribute var) {
Integer r = amap.get(var);
if(r == null) {
String nm = built.symtab.get(var.name);
if(nm == null)
r = new Integer(-1);
else
r = new Integer(attrib(nm));
amap.put(var, r);
}
return(r.intValue());
}
public int attrib(Attribute var) {
int r = cattrib(var);
if(r < 0)
throw(new ProgramException("Attribute not found in symtab: " + var, this, null));
return(r);
}
}
}