/*
* 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 java.nio.*;
import haven.MorphedMesh.Morpher;
import haven.MorphedMesh.MorphedBuf;
public class MeshAnim {
public final Frame[] frames;
public final float len;
public MeshAnim(Frame[] frames, float len) {
this.frames = frames;
this.len = len;
}
public static class Frame {
public final float time;
public final int[] idx;
public final float[] pos, nrm;
public Frame(float time, int[] idx, float[] pos, float[] nrm) {
this.time = time;
this.idx = idx;
this.pos = pos;
this.nrm = nrm;
}
}
public boolean animp(FastMesh mesh) {
int min = -1, max = -1;
for(int i = 0; i < mesh.num * 3; i++) {
int vi = mesh.indb.get(i);
if(min < 0) {
min = max = vi;
} else {
if(vi < min)
min = vi;
else if(vi > max)
max = vi;
}
}
boolean[] used = new boolean[max + 1 - min];
for(int i = 0; i < mesh.num * 3; i++) {
int vi = mesh.indb.get(i);
used[vi - min] = true;
}
for(Frame f : frames) {
for(int i = 0; i < f.idx.length; i++) {
int vi = f.idx[i];
if((vi < min) || (vi > max))
continue;
if(used[f.idx[i] - min])
return(true);
}
}
return(false);
}
public class Anim implements Morpher.Factory {
public float time = 0.0f;
private Frame cf, nf;
private float a;
private int seq = 0;
public Anim() {
aupdate(0.0f);
}
public void aupdate(float time) {
if(time > len)
time = len;
float ct, nt;
int l = 0, r = frames.length;
while(true) {
int c = l + ((r - l) >> 1);
ct = frames[c].time;
nt = (c < frames.length - 1)?(frames[c + 1].time):len;
if(ct > time) {
r = c;
} else if(nt < time) {
l = c + 1;
} else {
cf = frames[c];
nf = frames[(c + 1) % frames.length];
if(nt == ct)
a = 0;
else
a = (time - ct) / (nt - ct);
break;
}
}
seq++;
}
public void tick(float dt) {
this.time += dt;
while(this.time > len)
this.time -= len;
aupdate(this.time);
}
public Morpher create(final MorphedBuf vb) {
return(new Morpher() {
int lseq = -1;
public boolean update() {
if(lseq == seq)
return(false);
lseq = seq;
return(true);
}
public void morphp(FloatBuffer dst, FloatBuffer src) {
Frame f;
float a;
if(dst != src) {
int l = dst.capacity();
for(int i = 0; i < l; i++)
dst.put(i, src.get(i));
}
f = cf;
a = 1.0f - Anim.this.a;
for(int i = 0, po = 0; i < f.idx.length; i++, po += 3) {
int vo = f.idx[i] * 3;
float x = dst.get(vo), y = dst.get(vo + 1), z = dst.get(vo + 2);
x += f.pos[po] * a; y += f.pos[po + 1] * a; z += f.pos[po + 2] * a;
dst.put(vo, x).put(vo + 1, y).put(vo + 2, z);
}
f = nf;
a = Anim.this.a;
for(int i = 0, po = 0; i < f.idx.length; i++, po += 3) {
int vo = f.idx[i] * 3;
float x = dst.get(vo), y = dst.get(vo + 1), z = dst.get(vo + 2);
x += f.pos[po] * a; y += f.pos[po + 1] * a; z += f.pos[po + 2] * a;
dst.put(vo, x).put(vo + 1, y).put(vo + 2, z);
}
}
public void morphd(FloatBuffer dst, FloatBuffer src) {
Frame f;
float a;
if(dst != src) {
int l = dst.capacity();
for(int i = 0; i < l; i++)
dst.put(i, src.get(i));
}
f = cf;
a = 1.0f - Anim.this.a;
for(int i = 0, po = 0; i < f.idx.length; i++, po += 3) {
int vo = f.idx[i] * 3;
float x = dst.get(vo), y = dst.get(vo + 1), z = dst.get(vo + 2);
x += f.nrm[po] * a; y += f.nrm[po + 1] * a; z += f.nrm[po + 2] * a;
dst.put(vo, x).put(vo + 1, y).put(vo + 2, z);
}
f = nf;
a = Anim.this.a;
for(int i = 0, po = 0; i < f.idx.length; i++, po += 3) {
int vo = f.idx[i] * 3;
float x = dst.get(vo), y = dst.get(vo + 1), z = dst.get(vo + 2);
x += f.nrm[po] * a; y += f.nrm[po + 1] * a; z += f.nrm[po + 2] * a;
dst.put(vo, x).put(vo + 1, y).put(vo + 2, z);
}
}
});
}
}
@Resource.LayerName("manim")
public static class Res extends Resource.Layer {
public final int id;
public final MeshAnim a;
public Res(Resource res, byte[] data) {
res.super();
Message buf = new Message(0, data);
id = buf.int16();
float len = buf.float32();
List<Frame> frames = new LinkedList<Frame>();
while(true) {
int t = buf.uint8();
if(t == 0)
break;
float tm = buf.float32();
int n = buf.uint16();
int[] idx = new int[n];
float[] pos = new float[n * 3];
float[] nrm = new float[n * 3];
int i = 0;
while(i < n) {
int st = buf.uint16();
int run = buf.uint16();
for(int o = 0; o < run; o++) {
idx[i] = st + o;
pos[(i * 3) + 0] = buf.float32();
pos[(i * 3) + 1] = buf.float32();
pos[(i * 3) + 2] = buf.float32();
nrm[(i * 3) + 0] = buf.float32();
nrm[(i * 3) + 1] = buf.float32();
nrm[(i * 3) + 2] = buf.float32();
i++;
}
}
frames.add(new Frame(tm, idx, pos, nrm));
}
a = new MeshAnim(frames.toArray(new Frame[0]), len);
}
public void init() {
}
}
}