/*
* 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.nio.*;
import haven.MorphedMesh.Morpher;
import haven.MorphedMesh.MorphedBuf;
import haven.Skeleton.Pose;
public class PoseMorph implements Morpher.Factory {
public final Pose pose;
private float[][] offs;
private int seq = -1;
public PoseMorph(Pose pose) {
this.pose = pose;
offs = new float[pose.skel().blist.length][16];
}
public static boolean boned(FastMesh mesh) {
BoneArray ba = mesh.vert.buf(BoneArray.class);
if(ba == null)
return(false);
for(int i = 0; i < mesh.num * 3; i++) {
if(ba.data.get(mesh.indb.get(i) * ba.n) != -1)
return(true);
}
return(false);
}
public static String boneidp(FastMesh mesh) {
BoneArray ba = mesh.vert.buf(BoneArray.class);
if(ba == null)
return(null);
int retb = -1;
for(int i = 0; i < mesh.num * 3; i++) {
int vi = mesh.indb.get(i) * ba.n;
int curb = ba.data.get(vi);
if(curb == -1)
return(null);
if(retb == -1)
retb = curb;
else if(retb != curb)
return(null);
if((ba.n != 1) && (ba.data.get(vi + 1) != -1))
return(null);
}
return(ba.names[retb]);
}
private void update() {
if(seq == pose.seq)
return;
seq = pose.seq;
for(int i = 0; i < offs.length; i++)
pose.boneoff(i, offs[i]);
}
public static class BoneArray extends VertexBuf.IntArray {
public final String[] names;
public BoneArray(int apv, IntBuffer data, String[] names) {
super(apv, data);
this.names = names;
}
public BoneArray dup() {return(new BoneArray(n, Utils.bufcp(data), Utils.splice(names, 0)));}
}
public static class WeightArray extends VertexBuf.FloatArray {
public WeightArray(int apv, FloatBuffer data) {
super(apv, data);
}
}
public Morpher create(final MorphedBuf vb) {
BoneArray ob = vb.from.buf(BoneArray.class);
BoneArray nb = vb.buf(BoneArray.class);
int[] xl = new int[nb.names.length];
for(int i = 0; i < xl.length; i++) {
Skeleton.Bone b = pose.skel().bones.get(nb.names[i]);
if(b == null)
throw(new RuntimeException("Bone \"" + nb.names[i] + "\" in vertex-buf reference does not exist in skeleton " + pose.skel()));
xl[i] = b.idx;
}
for(int i = 0; i < ob.data.capacity(); i++) {
if(ob.data.get(i) == -1)
nb.data.put(i, -1);
else
nb.data.put(i, xl[ob.data.get(i)]);
}
return(new Morpher() {
private int pseq = -1;
public boolean update() {
if(pseq == pose.seq)
return(false);
PoseMorph.this.update();
pseq = pose.seq;
return(true);
}
public void morphp(FloatBuffer dst, FloatBuffer src) {
BoneArray ba = vb.buf(BoneArray.class);
int apv = ba.n;
IntBuffer bl = ba.data;
FloatBuffer wl = vb.buf(WeightArray.class).data;
int vo = 0, ao = 0;
for(int i = 0; i < vb.num; i++) {
float opx = src.get(vo), opy = src.get(vo + 1), opz = src.get(vo + 2);
float npx = 0, npy = 0, npz = 0;
float rw = 1;
for(int o = 0; o < apv; o++) {
int bi = bl.get(ao + o);
if(bi < 0)
break;
float bw = wl.get(ao + o);
float[] xf = offs[bi];
npx += ((xf[ 0] * opx) + (xf[ 4] * opy) + (xf[ 8] * opz) + xf[12]) * bw;
npy += ((xf[ 1] * opx) + (xf[ 5] * opy) + (xf[ 9] * opz) + xf[13]) * bw;
npz += ((xf[ 2] * opx) + (xf[ 6] * opy) + (xf[10] * opz) + xf[14]) * bw;
rw -= bw;
}
npx += opx * rw; npy += opy * rw; npz += opz * rw;
dst.put(vo, npx); dst.put(vo + 1, npy); dst.put(vo + 2, npz);
vo += 3;
ao += apv;
}
}
public void morphd(FloatBuffer dst, FloatBuffer src) {
BoneArray ba = vb.buf(BoneArray.class);
int apv = ba.n;
IntBuffer bl = ba.data;
FloatBuffer wl = vb.buf(WeightArray.class).data;
int vo = 0, ao = 0;
for(int i = 0; i < vb.num; i++) {
float onx = src.get(vo), ony = src.get(vo + 1), onz = src.get(vo + 2);
float nnx = 0, nny = 0, nnz = 0;
float rw = 1;
for(int o = 0; o < apv; o++) {
int bi = bl.get(ao + o);
if(bi < 0)
break;
float bw = wl.get(ao + o);
float[] xf = offs[bi];
nnx += ((xf[ 0] * onx) + (xf[ 4] * ony) + (xf[ 8] * onz)) * bw;
nny += ((xf[ 1] * onx) + (xf[ 5] * ony) + (xf[ 9] * onz)) * bw;
nnz += ((xf[ 2] * onx) + (xf[ 6] * ony) + (xf[10] * onz)) * bw;
rw -= bw;
}
nnx += onx * rw; nny += ony * rw; nnz += onz * rw;
dst.put(vo, nnx); dst.put(vo + 1, nny); dst.put(vo + 2, nnz);
vo += 3;
ao += apv;
}
}
});
}
}