/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2015 Andreas Maschke This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This software 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.create.tina.variation.iflames; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jwildfire.base.Tools; public class IFlamesAnimatorMotionStore { private final Map<Float, StoreEntry> store = new HashMap<Float, StoreEntry>(); private static class StoreEntry { private static final int MAX_PERMANENT_STORE = 1000; private static final int INITIAL_CAPACITY = 10000; private final float dt; @SuppressWarnings("rawtypes") private List[] entries = new ArrayList[INITIAL_CAPACITY]; public StoreEntry(float pDt) { dt = pDt; } private int reserveAndGetStoreIndex(float pTime) { int index = Tools.FTOI(pTime / dt); if (index >= entries.length) { int newSize = (index / INITIAL_CAPACITY) * INITIAL_CAPACITY; if (newSize <= index) { newSize += INITIAL_CAPACITY; } @SuppressWarnings("rawtypes") List[] newEntries = new ArrayList[newSize]; System.arraycopy(entries, 0, newEntries, 0, entries.length); entries = newEntries; } return index; } public void storeToIndex(float pTime, List<Particle> pParticles) { int index = reserveAndGetStoreIndex(pTime); List<Particle> dest = new ArrayList<Particle>(); entries[index] = dest; for (Particle src : pParticles) { dest.add(src.makeCopy()); } for (int i = index - MAX_PERMANENT_STORE; i >= 0; i--) { @SuppressWarnings("unchecked") List<Particle> p = entries[i]; if (p != null) { p.clear(); entries[i] = null; } } } public float getMaxStoredMotionTime(float pReferenceTime) { int maxIndex = (int) (pReferenceTime / dt); if (maxIndex >= entries.length) { maxIndex = entries.length - 1; } for (int i = maxIndex; i >= 0; i--) { if (entries[i] != null) { return i * dt; } } return 0.0f; } public void readFromIndex(float pTime, List<Particle> pParticles) { int index = reserveAndGetStoreIndex(pTime); @SuppressWarnings("unchecked") List<Particle> srcParticles = entries[index]; if (pParticles.size() != srcParticles.size()) { throw new RuntimeException("Stored motion does not match (" + pParticles.size() + "!=" + srcParticles.size() + ")"); } for (int i = 0; i < pParticles.size(); i++) { pParticles.set(i, srcParticles.get(i).makeCopy()); } } } private StoreEntry getStoreEntry(float pDt) { Float key = Float.valueOf(pDt); StoreEntry res = store.get(key); if (res == null) { res = new StoreEntry(pDt); store.put(key, res); } return res; } public float getMaxStoredMotionTime(float pReferenceTime, float pDt) { StoreEntry storeEntry = getStoreEntry(pDt); return storeEntry.getMaxStoredMotionTime(pReferenceTime); } public void storeMotion(float pTime, float pDt, List<Particle> pParticles) { StoreEntry storeEntry = getStoreEntry(pDt); storeEntry.storeToIndex(pTime, pParticles); } public void readFromStore(float pTime, float pDt, List<Particle> pParticles) { StoreEntry storeEntry = getStoreEntry(pDt); storeEntry.readFromIndex(pTime, pParticles); } }