/* ** 2013 May 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. */ package info.ata4.bspsrc.modules; import info.ata4.bsplib.BspFileReader; import info.ata4.bsplib.entity.Entity; import info.ata4.bspsrc.VmfWriter; import info.ata4.bspsrc.modules.entity.Camera; import info.ata4.log.LogUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * VMF metadata control class. * * @author Nico Bergemann <barracuda415 at yahoo.de> */ public class VmfMeta extends ModuleDecompile { // logger private static final Logger L = LogUtils.getLogger(); // UID mappings private Map<Integer, Integer> faceUIDs = new HashMap<>(); private Map<Integer, Integer> origFaceUIDs = new HashMap<>(); private Map<Short, Integer> dispinfoUIDs = new HashMap<>(); // UID blacklist private Set<Integer> uidbl = new HashSet<>(); // VMF unique ID private int uid = 0; // visgroup list private List<String> visgroups = new ArrayList<>(); // camera list private List<Camera> cameras = new ArrayList<>(); private Entity worldspawn; private String comment; public VmfMeta(BspFileReader reader, VmfWriter writer) { super(reader, writer); worldspawn = bsp.entities.get(0); // check for existing map comment if (worldspawn.getValue("comment") != null) { L.log(Level.INFO, "Map comment: {0}", worldspawn.getValue("comment")); } } public Set<Integer> getUIDBlackList() { return uidbl; } /** * Returns a new VMF unique ID. * * @return UID */ public int getUID() { if (uidbl.isEmpty()) { return uid++; } else { // increment ID until it's not found in the blacklist anymore do { uid++; } while (uidbl.contains(uid)); return uid; } } /** * Returns the VMF UID for the corresponding face index. * It automatically looks up the original face if the split face wasn't found. * * @param iface face index * @return brush side ID or -1 if the index isn't mapped yet */ public int getFaceUID(int iface) { if (faceUIDs.containsKey(iface)) { return faceUIDs.get(iface); } else { // try origface int ioface = bsp.faces.get(iface).origFace; if (origFaceUIDs.containsKey(ioface)) { return origFaceUIDs.get(ioface); } } // not found return -1; } /** * Sets the VMF UID for the given face index. * * @param iface face index * @param id VMF UID generated by {@link #getUID} * @return previously mapped UID or <tt>null</tt> if there was no mapping */ public Integer setFaceUID(int iface, int id) { return faceUIDs.put(iface, id); } /** * Sets the VMF UID for the given original face index. * * @param iface face index * @param id VMF UID generated by {@link #getUID} * @return previously mapped UID or <tt>null</tt> if there was no mapping */ public Integer setOrigFaceUID(int iface, int id) { return origFaceUIDs.put(iface, id); } /** * Returns the VMF UID for the corresponding dispInfo index. * * @param idispinfo dispinfo index * @return brush side ID or -1 if the index isn't mapped yet */ public int getDispInfoUID(short idispinfo) { if (dispinfoUIDs.containsKey(idispinfo)) { return dispinfoUIDs.get(idispinfo); } // not found return -1; } /** * Sets the VMF UID for the given displacement info index. * * @param idispinfo dispinfo index * @param id VMF UID generated by {@link #getUID} * @return previously mapped UID or <tt>null</tt> if there was no mapping */ public Integer setDispInfoUID(short idispinfo, int id) { return dispinfoUIDs.put(idispinfo, id); } public void setComment(String comment) { this.comment = comment; } public String getComment() { return comment; } /** * Writes the worldspawn header */ public void writeWorldHeader() { writer.start("world"); writer.put("id", getUID()); writer.put(worldspawn); // write comment if (comment != null) { writer.put("comment", comment); } writer.put("classname", "worldspawn"); } /** * Writes the worldspawn footer */ public void writeWorldFooter() { writer.end("world"); } public void writeVisgroups() { if (visgroups.isEmpty()) { return; } String[] visgroupArray = visgroups.toArray(new String[0]); writer.start("visgroups"); for (String visgroup : visgroupArray) { writer.start("visgroup"); writer.put("name", visgroup); writer.put("visgroupid", visgroups.indexOf(visgroup)); writer.end("visgroup"); } writer.end("visgroups"); } public void writeMetaVisgroup(String visgroupName) { writer.start("editor"); writer.put("visgroupid", getVisgroupID(visgroupName)); writer.end("editor"); } public void writeMetaVisgroups(List<String> visgroupNames) { writer.start("editor"); for (String visgroupName : visgroupNames) { writer.put("visgroupid", getVisgroupID(visgroupName)); } writer.end("editor"); } public int getVisgroupID(String visgroupName) { if (!visgroups.contains(visgroupName)) { visgroups.add(visgroupName); } return visgroups.indexOf(visgroupName); } public void writeCameras() { writer.start("cameras"); if (cameras.isEmpty()) { writer.put("activecamera", -1); } else { writer.put("activecamera", 0); for (Camera camera : cameras) { writer.start("camera"); writer.put("position", camera.pos, 2); writer.put("look", camera.look, 2); writer.end("camera"); } } writer.end("cameras"); } public List<Camera> getCameras() { return cameras; } }