colorCache = new HashMap<>(4096);
+ for (int i = 1; i < newPalette.length; i++) {
+ colorCache.put(newPalette[i], (byte) i);
+ }
+ final IndexColorModel cm = new IndexColorModel(8, 256, newPalette, 0, useAlpha, 0, DataBuffer.TYPE_BYTE);
+ for (final PseudoBamFrameEntry frameInfo : framesList) {
+ final BufferedImage dstImage = new BufferedImage(frameInfo.getWidth(), frameInfo.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, cm);
+ final byte[] dstBuf = ((DataBufferByte) dstImage.getRaster().getDataBuffer()).getData();
+
+ final BufferedImage srcImage = frameInfo.getFrame();
+ if (srcImage.getType() == BufferedImage.TYPE_BYTE_INDEXED) {
+ // processing palette-based source image
+ final byte[] srcBuf = ((DataBufferByte) srcImage.getRaster().getDataBuffer()).getData();
+ final IndexColorModel srcColorModel = (IndexColorModel) srcImage.getColorModel();
+ final int[] srcColors = new int[srcColorModel.getMapSize()];
+ srcColorModel.getRGBs(srcColors);
+ for (int ofs = 0; ofs < srcBuf.length; ofs++) {
+ final int srcColorIdx = srcBuf[ofs] & 0xff;
+ final int color = srcColors[(srcColorIdx < srcColors.length) ? srcColorIdx : 0];
+ if (!PseudoBamDecoder.isTransparentColor(color, transparencyThreshold)) {
+ final byte colorIdx = colorCache.computeIfAbsent(color, c -> {
+ return (byte) ColorConvert.getNearestColor(color, newPalette, alphaWeight, ColorConvert.COLOR_DISTANCE_CIE94);
+ });
+ dstBuf[ofs] = colorIdx;
+ }
+ }
+ } else {
+ // processing truecolor source image
+ final int[] srcBuf = ((DataBufferInt) srcImage.getRaster().getDataBuffer()).getData();
+ for (int ofs = 0; ofs < srcBuf.length; ofs++) {
+ final int color = srcBuf[ofs];
+ if (!PseudoBamDecoder.isTransparentColor(color, transparencyThreshold)) {
+ final byte colorIdx = colorCache.computeIfAbsent(color, c -> {
+ return (byte) ColorConvert.getNearestColor(color, newPalette, alphaWeight, ColorConvert.COLOR_DISTANCE_CIE94);
+ });
+ dstBuf[ofs] = colorIdx;
+ }
+ }
+ }
+
+ // adding frame
+ final int dstFrameIdx = newDecoder.frameAdd(dstImage, new Point(frameInfo.getCenterX(), frameInfo.getCenterY()));
+ final PseudoBamFrameEntry dstFrameInfo = newDecoder.getFrameInfo(dstFrameIdx);
+ dstFrameInfo.setOption(PseudoBamDecoder.OPTION_BOOL_TRANSPARENTGREENFORCED, true);
+ for (final String option : frameInfo.getOptionNames()) {
+ dstFrameInfo.setOption(option, frameInfo.getOption(option));
+ }
+ }
+
+ // transfering bam cycles
+ newDecoder.getCyclesList().addAll(decoder.getCyclesList());
+
+ return newDecoder;
+ }
+
+ /**
+ * Specialization of the {@link BiFunction} interface for combining two source pixels to a destination pixel.
+ * The first parameter specifies the pixel of the current animation frame.
+ * The second parameter specifies the pixel of the overlaid animation frame.
+ * The resulting pixel value is stored in the output animation frame.
+ * Pixel format is {@code 0xAARRGGBB}.
+ */
+ @FunctionalInterface
+ public static interface OverlayFunc extends BiFunction {
+ }
+
+ /**
+ * Helper class that encodes a BAM resource path into a universal (URI) format.
+ */
+ public static class ResourcePath {
+ /**
+ * URI scheme for biffed game resources. The resource path is expected to contain the resource name as root element.
+ */
+ public static final String URI_SCHEME_RESOURCE = "res";
+ /**
+ * URI scheme for relative file path definitions. The path is expected to be relative to the game's root folder.
+ */
+ public static final String URI_SCHEME_RELPATH = "rel";
+
+ private final URI path;
+
+ /**
+ * Initializes the {@code ResourcePath} object with the specified resource.
+ *
+ * @param entry {@link ResourceEntry} containing the game resource or file path of the BAM resource.
+ * @throws Exception If the resource location could not be determined.
+ */
+ public ResourcePath(ResourceEntry entry) throws Exception {
+ Objects.requireNonNull(entry);
+ if (entry instanceof BIFFResourceEntry) {
+ this.path = new URI(URI_SCHEME_RESOURCE, "/" + entry.getResourceName(), null);
+ } else {
+ final Path resPath = entry.getActualPath();
+ if (resPath.startsWith(Profile.getGameRoot())) {
+ // try to store relative path if possible
+ final String relPath;
+ if ("\\".equals(Platform.FILE_SEPARATOR)) {
+ relPath = Profile.getGameRoot().relativize(resPath).toString().replace('\\', '/');
+ } else {
+ relPath = Profile.getGameRoot().relativize(resPath).toString();
+ }
+ this.path = new URI(URI_SCHEME_RELPATH, "/" + relPath, null);
+ } else {
+ this.path = resPath.toUri();
+ }
+ }
+ }
+
+ /**
+ * Initializes the {@code ResourcePath} object with the specified {@link URI}.
+ *
+ * @param uri {@link URI} instance that defines a resource location.
+ */
+ public ResourcePath(URI uri) {
+ this.path = Objects.requireNonNull(uri);
+ }
+
+ /** Returns the {@link URI} of the resource stored inside this object. */
+ public URI getURI() {
+ return path;
+ }
+
+ /** Returns {@code true} if this object points to a (biffed) game resource. */
+ public boolean isResource() {
+ return URI_SCHEME_RESOURCE.equals(path.getScheme());
+ }
+
+ /** Returns {@code true} if this object points to a relative file path. */
+ public boolean isRelativePath() {
+ return URI_SCHEME_RELPATH.equals(path.getScheme());
+ }
+
+ /**
+ * Decodes the ResourceString URI and returns it as a {@link ResourceEntry} object.
+ *
+ * @return A {@link ResourceEntry} object with the resource path definition. Returns {@code null} if the resource
+ * could not be resolved.
+ * @throws IllegalArgumentException if the object contains an illegal path definition.
+ * @throws FileSystemNotFoundException if the filesystem does not exist (e.g. a virtual DLC filesystem).
+ */
+ public ResourceEntry getResourceEntry() {
+ if (isResource()) {
+ // remove leading slash and decode semicolon
+ final String resourceName = path.getPath().substring(1).replace("%3B", ";");
+ return ResourceFactory.getResourceEntry(resourceName);
+ } else if (isRelativePath()) {
+ // remove leading slash and decode semicolon
+ final String resourceName = path.getPath().substring(1).replace("%3B", ";");
+ return new FileResourceEntry(Profile.getGameRoot().resolve(resourceName).normalize());
+ } else {
+ return new FileResourceEntry(Paths.get(path).normalize());
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(path);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ResourcePath other = (ResourcePath)obj;
+ return Objects.equals(path, other.path);
+ }
+
+ /**
+ * Returns the content of the resource path in URI format. Semicolons inside the URI string are encoded
+ * to prevent conflicts with the BAM Converter configuration format.
+ */
+ @Override
+ public String toString() {
+ return path.toString().replace(";", "%3B");
+ }
+ }
+
+ /**
+ * Table model for the JTable component of the preview UI with a subset of {@link List} methods.
+ */
+ public static class OverlayTableModel extends AbstractTableModel
+ implements Iterable> {
+ private final List> entries = new ArrayList<>();
+
+ public OverlayTableModel() {
+ }
+
+ @Override
+ public int getRowCount() {
+ return entries.size();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 2;
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ if (rowIndex < 0 || rowIndex >= entries.size()) {
+ throw new IndexOutOfBoundsException("Row out of bounds: " + rowIndex);
+ }
+ return (columnIndex == 0) ? entries.get(rowIndex).getValue0() : entries.get(rowIndex).getValue1();
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ return (column == 0) ? "Resource" : "Mode";
+ }
+
+ /** Adds a new entry with the specified arguments to the end of the table model. */
+ public void add(ResourceEntry resource, OverlayMode mode) {
+ add(entries.size(), resource, mode);
+ }
+
+ /** Inserts a new entry with the specified argument at the specified position in the table model. */
+ public void add(int index, ResourceEntry resource, OverlayMode mode) {
+ Objects.requireNonNull(resource);
+ Objects.requireNonNull(mode);
+ add(index, Couple.with(resource, mode));
+ }
+
+ /** Inserts a new entry at the specified position in the table model. */
+ public void add(int index, Couple item) {
+ Objects.requireNonNull(item);
+ entries.add(index, item);
+ fireTableRowsInserted(index, index);
+ }
+
+ /** Removes all entries from the table model. */
+ public void clear() {
+ final int size = entries.size();
+ if (size > 0) {
+ entries.clear();
+ fireTableDataChanged();
+ }
+ }
+
+ /** Returns the content of the entry at the specified position in the table model. */
+ public Couple get(int index) {
+ final Couple entry = entries.get(index);
+ final Couple retVal = Couple.with(entry.getValue0(), entry.getValue1());
+ return retVal;
+ }
+
+ /** Returns {@code true} if the table model contains no entries. */
+ public boolean isEmpty() {
+ return entries.isEmpty();
+ }
+
+ /** Returns a read-only iterator over the entries in the table model. */
+ @Override
+ public Iterator> iterator() {
+ return Collections.unmodifiableList(entries).iterator();
+ }
+
+ /** Removes the entry at the specified position in the table model. */
+ public Couple remove(int index) {
+ final Couple retVal = entries.remove(index);
+ fireTableRowsDeleted(index, index);
+ return retVal;
+ }
+
+ /** Replaces the {@link ResourceEntry} of the entry at the specified position in the table model. */
+ public ResourceEntry set(int index, ResourceEntry resource) {
+ Objects.requireNonNull(resource);
+ final ResourceEntry retVal = entries.get(index).setValue0(resource);
+ fireTableCellUpdated(index, 0);
+ return retVal;
+ }
+
+ /** Replaces the {@link OverlayMode} of the entry at the specified position in the table model. */
+ public OverlayMode set(int index, OverlayMode mode) {
+ Objects.requireNonNull(mode);
+ final OverlayMode retVal = entries.get(index).setValue1(mode);
+ fireTableCellUpdated(index, 1);
+ return retVal;
+ }
+
+ /** Replaces the content of the entry at the specified position in the table model. */
+ public Couple set(int index, ResourceEntry resource, OverlayMode mode) {
+ Objects.requireNonNull(resource);
+ Objects.requireNonNull(mode);
+ final Couple entry = entries.get(index);
+ final Couple retVal = Couple.with(entry.getValue0(), entry.getValue1());
+ entry.setValue0(resource);
+ entry.setValue1(mode);
+ fireTableRowsUpdated(index, index);
+ return retVal;
+ }
+ }
+
+ /**
+ * Interactive dialog for selecting an {@link OverlayMode}.
+ */
+ private static class OverlayModeSelection extends NewAbstractSettings implements ItemListener {
+ private static final String NO_CHANGE_NAME = "(No change)";
+ private static final String NO_CHANGE_DESC = "Keep the current overlay modes for all selected entries.";
+
+ private JComboBox cbMode;
+ private JTextArea descArea;
+
+ public OverlayModeSelection(Window parent, OverlayMode mode) {
+ super(parent, "Select Overlay Mode");
+ init(mode);
+ }
+
+ @Override
+ public OverlayMode getConfig() {
+ return cbMode.getItemAt(cbMode.getSelectedIndex());
+ }
+
+ private void init(OverlayMode mode) {
+ acceptButton().setText("Select");
+ acceptButton().setIcon(Icons.ICON_CHECK_16.getIcon());
+
+ final JLabel label = new JLabel("Select overlay mode:");
+ label.setLabelFor(cbMode);
+ label.setDisplayedMnemonic(KeyEvent.VK_S);
+
+ final OverlayMode[] items;
+ if (mode == null) {
+ items = new OverlayMode[OverlayMode.values().length + ((mode != null) ? 0 : 1)];
+ items[0] = null;
+ System.arraycopy(OverlayMode.values(), 0, items, 1, OverlayMode.values().length);
+ } else {
+ items = OverlayMode.values();
+ }
+ cbMode = new JComboBox<>(items);
+ cbMode.setRenderer(new DefaultListCellRenderer() {
+ @Override
+ public Component getListCellRendererComponent(JList> list, Object value, int index, boolean isSelected,
+ boolean cellHasFocus) {
+ final String item = (value != null) ? value.toString() : NO_CHANGE_NAME;
+ return super.getListCellRendererComponent(list, item, index, isSelected, cellHasFocus);
+ }
+ });
+ if (mode != null) {
+ cbMode.setSelectedItem(OverlayMode.getOrDefault(mode));
+ } else {
+ cbMode.setSelectedIndex(0);
+ }
+ cbMode.addItemListener(this);
+
+ descArea = new JTextArea();
+ descArea.setLineWrap(true);
+ descArea.setWrapStyleWord(true);
+ descArea.setEditable(false);
+ descArea.setBackground(label.getBackground());
+ final JScrollPane scroll = new JScrollPane(descArea);
+ scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ scroll.getVerticalScrollBar().setUnitIncrement(16);
+ scroll.setPreferredSize(new Dimension(label.getPreferredSize().width * 7 / 4, 6 * label.getPreferredSize().height));
+ scroll.setMinimumSize(scroll.getPreferredSize());
+ updateDesc(cbMode.getItemAt(cbMode.getSelectedIndex()));
+
+ final JPanel panelButtons = new JPanel(new FlowLayout(FlowLayout.TRAILING, 5, 5));
+ panelButtons.add(acceptButton());
+ panelButtons.add(rejectButton());
+
+ final GridBagConstraints c = new GridBagConstraints();
+ final JPanel panel = new JPanel(new GridBagLayout());
+ ViewerUtil.setGBC(c, 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE,
+ new Insets(10, 10, 3, 10), 0, 0);
+ panel.add(label, c);
+ ViewerUtil.setGBC(c, 0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.HORIZONTAL,
+ new Insets(0, 10, 10, 10), 0, 0);
+ panel.add(cbMode, c);
+ ViewerUtil.setGBC(c, 0, 2, 1, 1, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH,
+ new Insets(0, 10, 10, 10), 0, 0);
+ panel.add(scroll, c);
+ ViewerUtil.setGBC(c, 0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LAST_LINE_END, GridBagConstraints.NONE,
+ new Insets(0, 5, 5, 5), 0, 0);
+ panel.add(panelButtons, c);
+
+ final Container contentPane = getContentPane();
+ contentPane.add(panel);
+
+ pack();
+ setMinimumSize(getPreferredSize());
+ setLocationRelativeTo(getParent());
+ setCancelOnEscape(true);
+ setVisible(true);
+ }
+
+ private void updateDesc(OverlayMode mode) {
+ final String desc = (mode != null) ? mode.getDesc() : NO_CHANGE_DESC;
+ descArea.setText(desc);
+ descArea.setCaretPosition(0);
+ }
+
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getItem() instanceof OverlayMode) {
+ final OverlayMode mode = (OverlayMode) e.getItem();
+ updateDesc(mode);
+ }
+ }
+ }
+}
diff --git a/src/org/infinity/gui/converter/BamFilterOutputSplitted.java b/src/org/infinity/gui/converter/BamFilterOutputSplitted.java
index 8dc21c9c9..ca6969917 100644
--- a/src/org/infinity/gui/converter/BamFilterOutputSplitted.java
+++ b/src/org/infinity/gui/converter/BamFilterOutputSplitted.java
@@ -16,7 +16,6 @@
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.IndexColorModel;
-import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -30,10 +29,8 @@
import javax.swing.event.ChangeListener;
import org.infinity.gui.ViewerUtil;
-import org.infinity.resource.graphics.DxtEncoder;
import org.infinity.resource.graphics.PseudoBamDecoder;
import org.infinity.resource.graphics.PseudoBamDecoder.PseudoBamFrameEntry;
-import org.infinity.util.Logger;
import org.infinity.util.Misc;
import org.infinity.util.io.FileManager;
@@ -73,7 +70,7 @@ public boolean process(PseudoBamDecoder decoder) throws Exception {
}
@Override
- public PseudoBamFrameEntry updatePreview(PseudoBamFrameEntry entry) {
+ public PseudoBamFrameEntry updatePreview(int frameIndex, PseudoBamFrameEntry entry) {
// does not modify the source image
return entry;
}
@@ -395,7 +392,8 @@ private boolean applyEffect(PseudoBamDecoder decoder) throws Exception {
// converting segmented BAM structure
int suffix = suffixStart + segIdx * suffixStep;
- if (!convertBam(FileManager.resolve(String.format(fmtBamFileName, suffix)), segmentDecoder)) {
+ if (!BamFilterBaseOutput.convertBam(getConverter(), FileManager.resolve(String.format(fmtBamFileName, suffix)),
+ segmentDecoder)) {
throw new Exception(String.format("Error converting segment %d/%d", segIdx + 1, segmentCount));
}
@@ -458,35 +456,4 @@ private PseudoBamFrameEntry createFrameSegment(PseudoBamFrameEntry entry, Rectan
}
return retVal;
}
-
- // Exports the BAM specified by "decoder" into the filename "outFileName" using global settings
- private boolean convertBam(Path outFileName, PseudoBamDecoder decoder) throws Exception {
- if (getConverter() != null && outFileName != null && decoder != null) {
- if (getConverter().isBamV1Selected()) {
- // convert to BAM v1
- decoder.setOption(PseudoBamDecoder.OPTION_INT_RLEINDEX,
- getConverter().getPaletteDialog().getRleIndex());
- decoder.setOption(PseudoBamDecoder.OPTION_BOOL_COMPRESSED, getConverter().isBamV1Compressed());
- try {
- return decoder.exportBamV1(outFileName, getConverter().getProgressMonitor(),
- getConverter().getProgressMonitorStage());
- } catch (Exception e) {
- Logger.error(e);
- throw e;
- }
- } else {
- // convert to BAM v2
- DxtEncoder.DxtType dxtType = getConverter().getDxtType();
- int pvrzIndex = getConverter().getPvrzIndex();
- try {
- return decoder.exportBamV2(outFileName, dxtType, pvrzIndex, getConverter().getProgressMonitor(),
- getConverter().getProgressMonitorStage());
- } catch (Exception e) {
- Logger.error(e);
- throw e;
- }
- }
- }
- return false;
- }
}
diff --git a/src/org/infinity/gui/converter/BamFilterTransformCenter.java b/src/org/infinity/gui/converter/BamFilterTransformCenter.java
index 0132f2c36..d661fc777 100644
--- a/src/org/infinity/gui/converter/BamFilterTransformCenter.java
+++ b/src/org/infinity/gui/converter/BamFilterTransformCenter.java
@@ -175,7 +175,7 @@ public boolean setConfiguration(String config) {
}
@Override
- public PseudoBamFrameEntry updatePreview(PseudoBamFrameEntry frame) {
+ public PseudoBamFrameEntry updatePreview(int frameIndex, PseudoBamFrameEntry frame) {
return applyEffect(frame);
}
diff --git a/src/org/infinity/gui/converter/BamFilterTransformMirror.java b/src/org/infinity/gui/converter/BamFilterTransformMirror.java
index f5f08b51b..3bca692fd 100644
--- a/src/org/infinity/gui/converter/BamFilterTransformMirror.java
+++ b/src/org/infinity/gui/converter/BamFilterTransformMirror.java
@@ -49,7 +49,7 @@ public PseudoBamFrameEntry process(PseudoBamFrameEntry entry) throws Exception {
}
@Override
- public PseudoBamFrameEntry updatePreview(PseudoBamFrameEntry entry) {
+ public PseudoBamFrameEntry updatePreview(int frameIndex, PseudoBamFrameEntry entry) {
return applyEffect(entry);
}
diff --git a/src/org/infinity/gui/converter/BamFilterTransformResize.java b/src/org/infinity/gui/converter/BamFilterTransformResize.java
index 50d3c4526..09dfc46bc 100644
--- a/src/org/infinity/gui/converter/BamFilterTransformResize.java
+++ b/src/org/infinity/gui/converter/BamFilterTransformResize.java
@@ -98,7 +98,7 @@ public PseudoBamFrameEntry process(PseudoBamFrameEntry entry) throws Exception {
}
@Override
- public PseudoBamFrameEntry updatePreview(PseudoBamFrameEntry entry) {
+ public PseudoBamFrameEntry updatePreview(int frameIndex, PseudoBamFrameEntry entry) {
return applyEffect(entry);
}
diff --git a/src/org/infinity/gui/converter/BamFilterTransformRotate.java b/src/org/infinity/gui/converter/BamFilterTransformRotate.java
index e506b24e2..079b05882 100644
--- a/src/org/infinity/gui/converter/BamFilterTransformRotate.java
+++ b/src/org/infinity/gui/converter/BamFilterTransformRotate.java
@@ -79,7 +79,7 @@ public PseudoBamFrameEntry process(PseudoBamFrameEntry entry) throws Exception {
}
@Override
- public PseudoBamFrameEntry updatePreview(PseudoBamFrameEntry entry) {
+ public PseudoBamFrameEntry updatePreview(int frameIndex, PseudoBamFrameEntry entry) {
return applyEffect(entry);
}
diff --git a/src/org/infinity/gui/converter/BamFilterTransformTrim.java b/src/org/infinity/gui/converter/BamFilterTransformTrim.java
index ce528eb8a..e9a6a2143 100644
--- a/src/org/infinity/gui/converter/BamFilterTransformTrim.java
+++ b/src/org/infinity/gui/converter/BamFilterTransformTrim.java
@@ -81,7 +81,7 @@ public PseudoBamFrameEntry process(PseudoBamFrameEntry entry) throws Exception {
}
@Override
- public PseudoBamFrameEntry updatePreview(PseudoBamFrameEntry entry) {
+ public PseudoBamFrameEntry updatePreview(int frameIndex, PseudoBamFrameEntry entry) {
return applyEffect(entry);
}
diff --git a/src/org/infinity/gui/converter/ConvertToBam.java b/src/org/infinity/gui/converter/ConvertToBam.java
index f86a1ad6d..1b448d6a5 100644
--- a/src/org/infinity/gui/converter/ConvertToBam.java
+++ b/src/org/infinity/gui/converter/ConvertToBam.java
@@ -2676,7 +2676,7 @@ private boolean framesAddImage(int listIndex, ResourceEntry entry, int frameInde
image = dstImage;
}
- // Workaround for BAMV1 transparency, see PseudoBamDecoder.OPTION_BOOL_TRANSPARENTGREENFORCED
+ // Workaround for BAM V1 transparency, see PseudoBamDecoder.OPTION_BOOL_TRANSPARENTGREENFORCED
final boolean forceTransparentGreen = image.getType() != BufferedImage.TYPE_BYTE_INDEXED;
modelFrames.insert(listIndex + curFrameIdx, image, new Point(), forceTransparentGreen);
// setting required extra options
@@ -3652,7 +3652,7 @@ private void filterUpdatePreviewFrameIndex() {
int max = ((Integer) model.getMaximum());
int cur = ((Integer) model.getValue());
if (max != listFrameEntries.get(BAM_ORIGINAL).size()) {
- max = listFrameEntries.get(BAM_ORIGINAL).size();
+ max = listFrameEntries.get(BAM_ORIGINAL).size() - 1;
if (cur >= max) {
cur = Math.max(max - 1, 0);
}
@@ -3967,7 +3967,7 @@ private PseudoBamFrameEntry getFilteredBamFrame(int bamVersion, int frameIdx, bo
for (int i = 0; i < curFilterIdx; i++) {
if (modelFilters.get(i) != null) {
BamFilterBase filter = modelFilters.get(i);
- entry = filter.updatePreview(entry);
+ entry = filter.updatePreview(frameIdx, entry);
}
}
entryFilterPreview.setFrame(entry.getFrame());
@@ -3982,7 +3982,7 @@ private PseudoBamFrameEntry getFilteredBamFrame(int bamVersion, int frameIdx, bo
entryFilterPreview.getCenterX(), entryFilterPreview.getCenterY());
BamFilterBase filter = modelFilters.get(curFilterIdx);
if (filter != null) {
- entry = filter.updatePreview(entry);
+ entry = filter.updatePreview(frameIdx, entry);
}
}
@@ -5131,7 +5131,7 @@ public boolean importData(Path session, boolean silent) {
/** Loads data from the specified file without user-interaction and optionally without feedback. */
private boolean loadData(Path inFile, boolean silent) {
if (inFile != null) {
- IniMap ini = new IniMap(new FileResourceEntry(inFile));
+ IniMap ini = new IniMap(new FileResourceEntry(inFile), true);
try {
// checking integrity