/*
* @(#)AmigaVideoFormatKeys.java
*
* Copyright (c) 2011 Werner Randelshofer, Goldau, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance onlyWith the
* license agreement you entered into onlyWith Werner Randelshofer.
* For details see accompanying license terms.
*/
package org.monte.media.anim;
import org.monte.media.Format;
import org.monte.media.FormatKey;
import org.monte.media.VideoFormatKeys;
import org.monte.media.math.Rational;
import java.util.ArrayList;
import java.util.Iterator;
/**
* {@code AmigaVideoFormatKeys}.
*
* @author Werner Randelshofer
* @version $Id$
*/
public class AmigaVideoFormatKeys extends VideoFormatKeys {
/** The Amiga monitor id.
*/
public final static FormatKey<Integer> MonitorIdKey = new FormatKey<Integer>("monitorId", Integer.class);
/** Anim Op5 . */
public static final String ENCODING_ANIM_OP5 = "op5";
enum ColorMode {
HAM, EHB, NORMAL
}
public final static FormatKey<ColorMode> ColorModeKey = new FormatKey<ColorMode>("colorMode", ColorMode.class);
public static Format fromCAMG(int camg) {
AmigaDisplayInfo i = AmigaDisplayInfo.getInfo(camg);
return new Format(
MediaTypeKey, MediaType.VIDEO,
EncodingKey, ENCODING_BITMAP_IMAGE,
WidthKey, i.textOverscanWidth,
HeightKey, i.textOverscanHeight,
MonitorIdKey, camg & AmigaDisplayInfo.MONITOR_ID_MASK,
ColorModeKey, i.isEHB() ? ColorMode.EHB : (i.isHAM() ? ColorMode.HAM : ColorMode.NORMAL),
InterlaceKey, i.isInterlace(),
PixelAspectRatioKey, new Rational(i.resolutionX, i.resolutionY),
FrameRateKey, new Rational(i.fps, 1));
}
public static int toCAMG(Format fmt) {
int camg = 0;
// determine monitor id
int monitorId = 0;
if (fmt.containsKey(MonitorIdKey)) {
monitorId = fmt.get(MonitorIdKey);
} else {
ArrayList<AmigaDisplayInfo> infs = new ArrayList<AmigaDisplayInfo>(AmigaDisplayInfo.getAllInfos().values());
if (fmt.containsKey(InterlaceKey)) {
boolean value = fmt.get(InterlaceKey);
reduceListBoolean(value, new InfGetter<Boolean>() {
@Override
public Boolean get(AmigaDisplayInfo inf) {
return inf.isInterlace();
}
}, infs);
}
if (fmt.containsKey(FrameRateKey)) {
Rational value = fmt.get(FrameRateKey);
reduceListRational(value, new InfGetter<Rational>() {
@Override
public Rational get(AmigaDisplayInfo inf) {
return new Rational(inf.fps, 1);
}
}, infs);
}
if (fmt.containsKey(PixelAspectRatioKey)) {
Rational value = fmt.get(PixelAspectRatioKey);
reduceListRational(value, new InfGetter<Rational>() {
@Override
public Rational get(AmigaDisplayInfo inf) {
return new Rational(inf.resolutionX, inf.resolutionY);
}
}, infs);
}
ArrayList<AmigaDisplayInfo> bestInfs = new ArrayList<AmigaDisplayInfo>(infs);
if (fmt.containsKey(WidthKey)) {
int value = fmt.get(WidthKey);
reduceListIntegerOnlyTakeIfSmaller(value, new InfGetter<Integer>() {
@Override
public Integer get(AmigaDisplayInfo inf) {
return inf.textOverscanWidth;
}
}, infs);
}
if (fmt.containsKey(HeightKey)) {
Integer value = fmt.get(HeightKey);
reduceListIntegerOnlyTakeIfSmaller(value, new InfGetter<Integer>() {
@Override
public Integer get(AmigaDisplayInfo inf) {
return inf.textOverscanHeight;
}
}, infs);
}
if (infs.isEmpty()) {
infs = new ArrayList<AmigaDisplayInfo>(bestInfs);
if (fmt.containsKey(WidthKey)) {
Integer value = fmt.get(WidthKey);
reduceListIntegerOnlyTakeIfSmaller(value, new InfGetter<Integer>() {
@Override
public Integer get(AmigaDisplayInfo inf) {
return inf.maxOverscanWidth;
}
}, infs);
}
if (fmt.containsKey(HeightKey)) {
Integer value = fmt.get(HeightKey);
reduceListIntegerOnlyTakeIfSmaller(value, new InfGetter<Integer>() {
@Override
public Integer get(AmigaDisplayInfo inf) {
return inf.maxOverscanHeight;
}
}, infs);
}
}
if (infs.isEmpty()) {
infs = new ArrayList<AmigaDisplayInfo>(bestInfs);
if (fmt.containsKey(WidthKey)) {
Integer value = fmt.get(WidthKey);
reduceListInteger(value, new InfGetter<Integer>() {
@Override
public Integer get(AmigaDisplayInfo inf) {
return inf.maxOverscanWidth;
}
}, infs);
}
if (fmt.containsKey(HeightKey)) {
Integer value = fmt.get(HeightKey);
reduceListInteger(value, new InfGetter<Integer>() {
@Override
public Integer get(AmigaDisplayInfo inf) {
return inf.maxOverscanHeight;
}
}, infs);
}
}
}
int colorMode=0;
if (fmt.containsKey(ColorModeKey)) {
switch (fmt.get(ColorModeKey)) {
case EHB:
colorMode=AmigaDisplayInfo.EHB_COLORMODE;
break;
case HAM:
colorMode=AmigaDisplayInfo.HAM_COLORMODE;
break;
case NORMAL:
break;
}
}
camg = monitorId|colorMode;
return camg;
}
private interface InfGetter<T> {
public T get(AmigaDisplayInfo inf);
}
private static void reduceListRational(Rational value, InfGetter<Rational> g, ArrayList<AmigaDisplayInfo> infs) {
ArrayList<AmigaDisplayInfo> bestInfs = new ArrayList<AmigaDisplayInfo>();
bestInfs.add(infs.get(0));
float bestCost = g.get(infs.get(0)).subtract(value).floatValue();
bestCost *= bestCost;
for (Iterator<AmigaDisplayInfo> i = infs.iterator(); i.hasNext();) {
AmigaDisplayInfo inf = i.next();
Rational iv = g.get(inf);
if (iv.compareTo(value) != 0) {
i.remove();
}
float icost = iv.subtract(value).floatValue();
icost *= icost;
if (icost < bestCost) {
bestInfs.clear();
bestCost = icost;
} else if (icost == bestCost) {
bestInfs.add(inf);
}
}
if (infs.isEmpty()) {
infs.addAll(bestInfs);
}
}
private static void reduceListInteger(int value, InfGetter<Integer> g, ArrayList<AmigaDisplayInfo> infs) {
ArrayList<AmigaDisplayInfo> bestInfs = new ArrayList<AmigaDisplayInfo>();
bestInfs.add(infs.get(0));
float bestCost = g.get(infs.get(0)) - value;
bestCost *= bestCost;
for (Iterator<AmigaDisplayInfo> i = infs.iterator(); i.hasNext();) {
AmigaDisplayInfo inf = i.next();
int iv = g.get(inf);
if (iv != value) {
i.remove();
}
float icost = iv - value;
icost *= icost;
if (icost < bestCost) {
bestInfs.clear();
bestCost = icost;
} else if (icost == bestCost) {
bestInfs.add(inf);
}
}
if (infs.isEmpty()) {
infs.addAll(bestInfs);
}
}
private static void reduceListIntegerOnlyTakeIfSmaller(int value, InfGetter<Integer> g, ArrayList<AmigaDisplayInfo> infs) {
reduceListInteger(value, g, infs);
for (Iterator<AmigaDisplayInfo> i = infs.iterator(); i.hasNext();) {
AmigaDisplayInfo inf = i.next();
int iv = g.get(inf);
if (value > iv) {
i.remove();
}
}
}
private static void reduceListBoolean(boolean value, InfGetter<Boolean> g, ArrayList<AmigaDisplayInfo> infs) {
for (Iterator<AmigaDisplayInfo> i = infs.iterator(); i.hasNext();) {
AmigaDisplayInfo inf = i.next();
boolean iv = g.get(inf);
if (iv != value) {
i.remove();
}
}
}
}