/* * Copyright 2016 Nathan Howard * * This file is part of OpenGrave * * OpenGrave is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenGrave 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. * * You should have received a copy of the GNU General Public License * along with OpenGrave. If not, see <http://www.gnu.org/licenses/>. */ package com.opengrave.og.models; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.opengrave.og.util.Matrix4f; public class DAEAnimChannelCollection { public boolean ignore = false; ArrayList<DAEAnimChannel> channels = new ArrayList<DAEAnimChannel>(); public ArrayList<DAEAnimKeyframeData> data = new ArrayList<DAEAnimKeyframeData>(); Pattern numberInBrackets; public String target; public void add(DAEAnimChannel animchannel) { channels.add(animchannel); } public void prepare() { if (numberInBrackets == null) { numberInBrackets = Pattern.compile("\\((\\d+)\\)"); } if (channels.size() == 0) { System.out.println("Failed to prepare animation keyframes. No channels"); return; } // Get a list of all timestamps in all of the given channel sections // that make this ArrayList<Float> timeStamps = new ArrayList<Float>(); for (DAEAnimChannel channel : channels) { for (Float time : channel.sampler.input.floatList) { if (!timeStamps.contains(time)) { timeStamps.add(time); } } } // Organise timestamps to be in order again Collections.sort(timeStamps, new Comparator<Float>() { public int compare(Float f1, Float f2) { if (f1 < f2) { return -1; } else if (f1 == f2) { return 0; } else { return 1; } } }); // Iterate through timestamps for (Float time : timeStamps) { DAEAnimKeyframeData keyframe = new DAEAnimKeyframeData(); keyframe.time = time; for (DAEAnimChannel channel : channels) { if (channel.target.toLowerCase().startsWith("transform(")) { Float value = channel.sampler.interpTime(time); int first = -1, second = -1; Matcher m = numberInBrackets.matcher(channel.target); if (m.find()) { first = Integer.parseInt(m.group(1)); } if (m.find()) { second = Integer.parseInt(m.group(1)); } if (first == -1 || second == -1) { System.out.println("Failed getting Matrix indexes for " + channel.target); } keyframe.transform = keyframe.transform.put(first, second, value); } else if (channel.target.toLowerCase().endsWith("transform")) { keyframe.transform = channel.sampler.interpTimeMatrix(time); } // TODO Deal with exporters who output in other targets. } // Avoid a common bug with scale if (keyframe.transform != null) { keyframe.transform.put(3, 3, 1f); } data.add(keyframe); } Matrix4f first = data.get(0).transform; boolean allEqual = true; for (DAEAnimKeyframeData keyframe : data) { if (first.equals(keyframe.transform)) { allEqual = false; break; } } if (allEqual) { ignore = true; } // Delete Loaded data from Files. channels = null; } public float lastKeyframeTime() { return data.get(data.size() - 1).time; } public Matrix4f get(float poseTime) { int lastIndex = data.size() - 1; int startIndex = 0, endIndex = lastIndex; float startTime = 0f, endTime = data.get(lastIndex).time; for (int i = 0; i < data.size(); i++) { if (data.get(i).time < poseTime) { startIndex = i; startTime = data.get(i).time; } else if (data.get(i).time == poseTime) { return data.get(i).transform; } else { endIndex = i; endTime = data.get(i).time; break; } } float diffTime = endTime - startTime; float interp = (poseTime - startTime) / diffTime; Matrix4f m1 = data.get(startIndex).transform; Matrix4f m2 = data.get(endIndex).transform; if (diffTime <= 0f) { return m1; } Matrix4f result = m1.interp(m2, interp, null); return result; } }