/* * 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 java.util.*; import haven.Skeleton.Pose; import haven.Skeleton.PoseMod; public class Composited implements Rendered { public final Skeleton skel; public final Pose pose; private final PoseMorph morph; private Collection<Model> mod = new LinkedList<Model>(); private Collection<Equ> equ = new LinkedList<Equ>(); public Poses poses = new Poses(); public List<MD> nmod = null, cmod = new LinkedList<MD>(); public List<ED> nequ = null, cequ = new LinkedList<ED>(); public class Poses { private final PoseMod[] mods; Pose old; float ipold = 0.0f, ipol = 0.0f; public float limit = -1.0f; public boolean stat, ldone; public Poses() { this.mods = new PoseMod[0]; } public Poses(List<? extends PoseMod> mods) { this.mods = mods.toArray(new PoseMod[0]); stat = true; for(PoseMod mod : this.mods) { if(!mod.stat()) { stat = false; break; } } } private void rebuild() { pose.reset(); for(PoseMod m : mods) m.apply(pose); if(ipold > 0.0f) pose.blend(old, ipold); pose.gbuild(); } public void set(float ipol) { if((this.ipol = ipol) > 0) { this.old = skel.new Pose(pose); this.ipold = 1.0f; } Composited.this.poses = this; rebuild(); } public void tick(float dt) { boolean build = false; if(limit >= 0) { if((limit -= dt) < 0) ldone = true; } boolean done = ldone; for(PoseMod m : mods) { m.tick(dt); if(!m.done()) done = false; } if(!stat) build = true; if(ipold > 0.0f) { if((ipold -= (dt / ipol)) < 0.0f) { ipold = 0.0f; old = null; } build = true; } if(build) rebuild(); if(done) done(); } @Deprecated public void tick(float dt, double v) {tick(dt);} protected void done() {} } public Composited(Skeleton skel) { this.skel = skel; this.pose = skel.new Pose(skel.bindpose); this.morph = new PoseMorph(pose); } private static final Rendered.Order modorder = new Rendered.Order<Model.Layer>() { public int mainz() { return(1); } private final Rendered.RComparator<Model.Layer> cmp = new Rendered.RComparator<Model.Layer>() { public int compare(Model.Layer a, Model.Layer b, GLState.Buffer sa, GLState.Buffer sb) { if(a.z1 != b.z1) return(a.z1 - b.z1); return(a.z2 - b.z2); } }; public Rendered.RComparator<Model.Layer> cmp() { return(cmp); } }; private class Model implements Rendered { private final MorphedMesh m; int z = 0, lz = 0; private class Layer implements FRendered { private final Material mat; private final int z1, z2; private Layer(Material mat, int z1, int z2) { this.mat = mat; this.z1 = z1; this.z2 = z2; } public void draw(GOut g) { m.draw(g); } public void drawflat(GOut g) { if(z2 == 0) m.drawflat(g); } public boolean setup(RenderList r) { r.prepo(modorder); r.prepo(mat); return(true); } } private final List<Layer> lay = new ArrayList<Layer>(); private Model(FastMesh m) { this.m = new MorphedMesh(m, morph); } private void addlay(Material mat) { lay.add(new Layer(mat, z, lz++)); } public void draw(GOut g) { } public boolean setup(RenderList r) { m.setup(r); for(Layer lay : this.lay) r.add(lay, null); return(false); } } private class SpriteEqu extends Equ { private final Sprite spr; private SpriteEqu(ED ed) { super(ed); this.spr = Sprite.create(null, ed.res.get(), new Message(0)); } public void draw(GOut g) { } public boolean setup(RenderList rl) { rl.add(spr, null); return(false); } public void tick(int dt) { spr.tick(dt); } } private class LightEqu extends Equ { private final Light l; private LightEqu(ED ed) { super(ed); this.l = ed.res.get().layer(Light.Res.class).make(); } public void draw(GOut g) { } public boolean setup(RenderList rl) { rl.add(l, null); return(false); } } private abstract class Equ implements Rendered { private final GLState et; private Equ(ED ed) { Skeleton.BoneOffset bo = ed.res.get().layer(Skeleton.BoneOffset.class, ed.at); GLState bt; if(bo != null) { bt = bo.forpose(pose); } else { Skeleton.Bone bone = skel.bones.get(ed.at); bt = pose.bonetrans(bone.idx); } if((ed.off.x != 0.0f) || (ed.off.y != 0.0f) || (ed.off.z != 0.0f)) this.et = GLState.compose(bt, Location.xlate(ed.off)); else this.et = bt; } public void tick(int dt) {} } public static class MD implements Cloneable { public Indir<Resource> mod; public List<Indir<Resource>> tex; private Model real; public MD(Indir<Resource> mod, List<Indir<Resource>> tex) { this.mod = mod; this.tex = tex; } public boolean equals(Object o) { if(!(o instanceof MD)) return(false); MD m = (MD)o; return(mod.equals(m.mod) && tex.equals(m.tex)); } public MD clone() { try { MD ret = (MD)super.clone(); ret.tex = new LinkedList<Indir<Resource>>(tex); return(ret); } catch(CloneNotSupportedException e) { /* This is ridiculous. */ throw(new RuntimeException(e)); } } public String toString() { return(mod + "+" + tex); } } public static class ED implements Cloneable { public int t; public String at; public Indir<Resource> res; public Coord3f off; public ED(int t, String at, Indir<Resource> res, Coord3f off) { this.t = t; this.at = at; this.res = res; this.off = off; } public boolean equals(Object o) { if(!(o instanceof ED)) return(false); ED e = (ED)o; return((t == e.t) && at.equals(e.at) && res.equals(e.res)); } public ED clone() { try { ED ret = (ED)super.clone(); return(ret); } catch(CloneNotSupportedException e) { /* This is ridiculous. */ throw(new RuntimeException(e)); } } } private void nmod(boolean nocatch) { for(Iterator<MD> i = nmod.iterator(); i.hasNext();) { MD md = i.next(); try { if(md.real == null) { FastMesh.MeshRes mr = md.mod.get().layer(FastMesh.MeshRes.class); md.real = new Model(mr.m); /* This is really ugly, but I can't really think of * anything less ugly right now. */ if(md.mod.get().name.equals("gfx/borka/male") || md.mod.get().name.equals("gfx/borka/female")) md.real.z = -1; this.mod.add(md.real); } for(Iterator<Indir<Resource>> o = md.tex.iterator(); o.hasNext();) { Indir<Resource> res = o.next(); for(Material.Res mr : res.get().layers(Material.Res.class)) md.real.addlay(mr.get()); o.remove(); } i.remove(); } catch(Loading e) { if(nocatch) throw(e); } } if(nmod.isEmpty()) nmod = null; } private void nequ(boolean nocatch) { for(Iterator<ED> i = nequ.iterator(); i.hasNext();) { ED ed = i.next(); try { if(ed.t == 0) this.equ.add(new SpriteEqu(ed)); else if(ed.t == 1) this.equ.add(new LightEqu(ed)); i.remove(); } catch(Loading e) { if(nocatch) throw(e); } } if(nequ.isEmpty()) nequ = null; } public void changes(boolean nocatch) { if(nmod != null) nmod(nocatch); if(nequ != null) nequ(nocatch); } public void changes() { changes(false); } public boolean setup(RenderList rl) { changes(); for(Model mod : this.mod) rl.add(mod, null); for(Equ equ : this.equ) rl.add(equ, equ.et); return(false); } public void draw(GOut g) { } public void tick(int dt) { if(poses != null) poses.tick(dt / 1000.0f); for(Equ equ : this.equ) equ.tick(dt); } @Deprecated public void tick(int dt, double v) {tick(dt);} public void chmod(List<MD> mod) { if(mod.equals(cmod)) return; this.mod = new LinkedList<Model>(); nmod = new LinkedList<MD>(); for(MD md : mod) nmod.add(md.clone()); cmod = new ArrayList<MD>(mod); } public void chequ(List<ED> equ) { if(equ.equals(cequ)) return; this.equ = new LinkedList<Equ>(); nequ = new LinkedList<ED>(); for(ED ed : equ) nequ.add(ed.clone()); cequ = new ArrayList<ED>(equ); } }