/* * 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; import haven.glsl.Attribute; import java.awt.Color; import java.util.*; import java.nio.*; public class MeshBuf { public final Collection<Vertex> v = new ArrayList<Vertex>(); public final Collection<Face> f = new ArrayList<Face>(); private VertexBuf vbuf = null; private int nextid = 0; private Layer<?>[] layers = new Layer<?>[0]; private LayerID<?>[] lids = new LayerID<?>[0]; public abstract class Layer<T> { public final int idx; public Layer() { idx = nextid++; layers = Utils.extend(layers, nextid); lids = Utils.extend(lids, nextid); layers[idx] = this; for(Vertex o : v) o.attrs = Utils.extend(o.attrs, nextid); } public void set(Vertex v, T data) { v.attrs[idx] = data; } @SuppressWarnings("unchecked") public T get(Vertex v) { return((T)v.attrs[idx]); } public abstract VertexBuf.AttribArray build(Collection<T> in); public void copy(VertexBuf src, Vertex[] vmap, int off) {} } public static abstract class LayerID<L> { public abstract L cons(MeshBuf buf); } public static class CLayerID<L> extends LayerID<L> { public final Class<L> cl; private final java.lang.reflect.Constructor<L> cons; public CLayerID(Class<L> cl) { this.cl = cl; try { this.cons = cl.getConstructor(MeshBuf.class); } catch(NoSuchMethodException e) { throw(new RuntimeException(e)); } } public L cons(MeshBuf buf) { return(Utils.construct(cons, buf)); } } public class Tex extends Layer<Coord3f> { public VertexBuf.TexelArray build(Collection<Coord3f> in) { FloatBuffer data = Utils.wfbuf(in.size() * 2); for(Coord3f c : in) { data.put(c.x); data.put(c.y); } return(new VertexBuf.TexelArray(data)); } public void copy(VertexBuf buf, Vertex[] vmap, int off) { VertexBuf.TexelArray src = buf.buf(VertexBuf.TexelArray.class); if(src == null) return; for(int i = 0, o = off * 2; i < vmap.length; i++, o += 2) { if(vmap[i] != null) set(vmap[i], new Coord3f(src.data.get(o), src.data.get(o + 1), 0)); } } } public static final LayerID<Tex> tex = new CLayerID<Tex>(Tex.class); public class Col extends Layer<Color> { public VertexBuf.ColorArray build(Collection<Color> in) { FloatBuffer data = Utils.wfbuf(in.size() * 4); for(Color c : in) { data.put(c.getRed() / 255.0f); data.put(c.getGreen() / 255.0f); data.put(c.getBlue() / 255.0f); data.put(c.getAlpha() / 255.0f); } return(new VertexBuf.ColorArray(data)); } } public static final LayerID<Col> col = new CLayerID<Col>(Col.class); public abstract class AttribLayer<T> extends Layer<T> { public final Attribute attrib; public AttribLayer(Attribute attrib) { this.attrib = attrib; } } public class Vec1Layer extends AttribLayer<Float> { public Vec1Layer(Attribute attrib) {super(attrib);} public VertexBuf.Vec1Array build(Collection<Float> in) { FloatBuffer data = Utils.wfbuf(in.size()); for(Float d : in) data.put(d); return(new VertexBuf.Vec1Array(data, attrib)); } } public class Vec2Layer extends AttribLayer<Coord3f> { public Vec2Layer(Attribute attrib) {super(attrib);} public VertexBuf.Vec2Array build(Collection<Coord3f> in) { FloatBuffer data = Utils.wfbuf(in.size() * 2); for(Coord3f d : in) { data.put(d.x); data.put(d.y); } return(new VertexBuf.Vec2Array(data, attrib)); } } public class Vec3Layer extends AttribLayer<Coord3f> { public Vec3Layer(Attribute attrib) {super(attrib);} public VertexBuf.Vec3Array build(Collection<Coord3f> in) { FloatBuffer data = Utils.wfbuf(in.size() * 3); for(Coord3f d : in) { data.put(d.x); data.put(d.y); data.put(d.z); } return(new VertexBuf.Vec3Array(data, attrib)); } } public class Vec4Layer extends AttribLayer<float[]> { public Vec4Layer(Attribute attrib) {super(attrib);} public VertexBuf.Vec4Array build(Collection<float[]> in) { FloatBuffer data = Utils.wfbuf(in.size() * 4); for(float[] d : in) { data.put(d[0]); data.put(d[1]); data.put(d[2]); data.put(d[3]); } return(new VertexBuf.Vec4Array(data, attrib)); } } public static abstract class ALayerID<L> extends LayerID<L> { public final Attribute attrib; public ALayerID(Attribute attrib) { this.attrib = attrib; } } public static class V1LayerID extends ALayerID<Vec1Layer> { public V1LayerID(Attribute attrib) {super(attrib);} public Vec1Layer cons(MeshBuf buf) {return(buf.new Vec1Layer(attrib));} } public static class V2LayerID extends ALayerID<Vec2Layer> { public V2LayerID(Attribute attrib) {super(attrib);} public Vec2Layer cons(MeshBuf buf) {return(buf.new Vec2Layer(attrib));} } public static class V3LayerID extends ALayerID<Vec3Layer> { public V3LayerID(Attribute attrib) {super(attrib);} public Vec3Layer cons(MeshBuf buf) {return(buf.new Vec3Layer(attrib));} } public static class V4LayerID extends ALayerID<Vec4Layer> { public V4LayerID(Attribute attrib) {super(attrib);} public Vec4Layer cons(MeshBuf buf) {return(buf.new Vec4Layer(attrib));} } @SuppressWarnings("unchecked") public <L extends Layer> L layer(LayerID<L> id) { if(id == null) throw(new NullPointerException()); for(int i = 0; i < lids.length; i++) { if(lids[i] == id) return((L)layers[i]); } L ret = id.cons(this); lids[ret.idx] = id; return(ret); } public class Vertex { public Coord3f pos, nrm; private Object[] attrs = new Object[layers.length]; private short idx; public Vertex(Coord3f pos, Coord3f nrm) { this.pos = pos; this.nrm = nrm; v.add(this); } public String toString() { return(String.format("MeshBuf.Vertex(%s, %s)", pos, nrm)); } } public class Face { public final Vertex v1, v2, v3; public Face(Vertex v1, Vertex v2, Vertex v3) { this.v1 = v1; this.v2 = v2; this.v3 = v3; f.add(this); } } public interface LayerMapper { public Layer mapbuf(MeshBuf buf, VertexBuf.AttribArray src); } public Vertex[] copy(FastMesh src, LayerMapper mapper) { int min = -1, max = -1; for(int i = 0; i < src.num * 3; i++) { int idx = src.indb.get(i); if((min < 0) || (idx < min)) min = idx; if(idx > max) max = idx; } int nv = 0; VertexBuf.VertexArray posb = src.vert.buf(VertexBuf.VertexArray.class); VertexBuf.NormalArray nrmb = src.vert.buf(VertexBuf.NormalArray.class); Vertex[] vmap = new Vertex[max + 1 - min]; for(int i = 0; i < src.num * 3; i++) { int idx = src.indb.get(i); if(vmap[idx - min] == null) { int o = idx * posb.n; Coord3f pos = new Coord3f(posb.data.get(o), posb.data.get(o + 1), posb.data.get(o + 2)); o = idx * nrmb.n; Coord3f nrm = new Coord3f(nrmb.data.get(o), nrmb.data.get(o + 1), nrmb.data.get(o + 2)); vmap[idx - min] = new Vertex(pos, nrm); nv++; } } for(VertexBuf.AttribArray data : src.vert.bufs) { Layer l = mapper.mapbuf(this, data); if(l != null) l.copy(src.vert, vmap, min); } for(int i = 0; i < src.num; i++) { int o = i * 3; new Face(vmap[src.indb.get(o) - min], vmap[src.indb.get(o + 1) - min], vmap[src.indb.get(o + 2) - min]); } Vertex[] vl = new Vertex[nv]; int n = 0; for(int i = 0; i < vmap.length; i++) { if(vmap[i] != null) vl[n++] = vmap[i]; } return(vl); } private static final LayerMapper defmapper = new LayerMapper() { public Layer mapbuf(MeshBuf buf, VertexBuf.AttribArray src) { if(src instanceof VertexBuf.TexelArray) return(buf.layer(tex)); return(null); } }; public Vertex[] copy(FastMesh src) { return(copy(src, defmapper)); } @SuppressWarnings("unchecked") private <T> VertexBuf.AttribArray mklayer(Layer<T> l, Object[] abuf) { int i = 0; boolean f = false; for(Vertex v : this.v) { if((abuf[i++] = v.attrs[l.idx]) != null) f = true; } if(!f) return(null); return(l.build(Arrays.asList((T[])abuf))); } private void mkvbuf() { if(v.isEmpty()) throw(new RuntimeException("Tried to build empty vertex buffer")); FloatBuffer pos, nrm; { pos = Utils.wfbuf(v.size() * 3); nrm = Utils.wfbuf(v.size() * 3); int pi = 0, ni = 0; short i = 0; for(Vertex v : this.v) { pos.put(pi + 0, v.pos.x); pos.put(pi + 1, v.pos.y); pos.put(pi + 2, v.pos.z); nrm.put(pi + 0, v.nrm.x); nrm.put(pi + 1, v.nrm.y); nrm.put(pi + 2, v.nrm.z); pi += 3; ni += 3; v.idx = i++; if(i == 0) throw(new RuntimeException("Too many vertices in meshbuf")); } } VertexBuf.AttribArray[] arrays = new VertexBuf.AttribArray[layers.length + 2]; int li = 0; arrays[li++] = new VertexBuf.VertexArray(pos); arrays[li++] = new VertexBuf.NormalArray(nrm); Object[] abuf = new Object[v.size()]; for(int i = 0; i < layers.length; i++) { VertexBuf.AttribArray l = mklayer(layers[i], abuf); if(l != null) arrays[li++] = l; } this.vbuf = new VertexBuf(Utils.splice(arrays, 0, li)); } public void clearfaces() { this.f.clear(); } public FastMesh mkmesh(int i) { if(f.isEmpty()) throw(new RuntimeException("Tried to build empty mesh")); if(this.vbuf == null) mkvbuf(); short[] idx = new short[f.size() * 3]; int ii = 0; for(Face f : this.f) { idx[ii + 0] = f.v1.idx; idx[ii + 1] = f.v2.idx; idx[ii + 2] = f.v3.idx; ii += 3; } if(i == MapView.WFOL) return(new WireMesh(this.vbuf, idx)); else return(new FastMesh(this.vbuf, idx)); } public FastMesh mkmesh() { return(mkmesh(-1)); } public boolean emptyp() { return(f.isEmpty()); } }