// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.resource.are.viewer;
import java.awt.Color;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.util.List;
import org.infinity.datatype.Flag;
import org.infinity.datatype.HexNumber;
import org.infinity.datatype.SectionCount;
import org.infinity.datatype.SectionOffset;
import org.infinity.datatype.TextString;
import org.infinity.gui.layeritem.AbstractLayerItem;
import org.infinity.gui.layeritem.ShapedLayerItem;
import org.infinity.resource.AbstractStruct;
import org.infinity.resource.Profile;
import org.infinity.resource.StructEntry;
import org.infinity.resource.Viewable;
import org.infinity.resource.vertex.Vertex;
import org.infinity.resource.wed.Door;
import org.infinity.resource.wed.WedResource;
/**
* Handles specific layer type: WED/Door Polygon
*/
public class LayerObjectDoorPoly extends LayerObject
{
private static final Color[] Color = {new Color(0xFF603080, true), new Color(0xFF603080, true),
new Color(0x80A050C0, true), new Color(0xC0C060D0, true)};
private final Door door;
private Point[] location;
private ShapedLayerItem[] items;
private Point[][] shapeCoords;
private int openCount;
public LayerObjectDoorPoly(WedResource parent, Door doorPoly)
{
super(ViewerConstants.RESOURCE_WED, "Door Poly", Door.class, parent);
this.door = doorPoly;
init();
}
@Override
public Viewable getViewable()
{
return door;
}
@Override
public Viewable[] getViewables()
{
return new Viewable[]{door};
}
@Override
public AbstractLayerItem getLayerItem()
{
if (items.length > 0) {
return items[0];
} else {
return null;
}
}
@Override
public AbstractLayerItem getLayerItem(int type)
{
if (Profile.getEngine() == Profile.Engine.PST) {
// open/closed states are inverted for PST
type = (type == ViewerConstants.DOOR_OPEN) ? ViewerConstants.DOOR_CLOSED : ViewerConstants.DOOR_OPEN;
} else {
type = (type == ViewerConstants.DOOR_OPEN) ? ViewerConstants.DOOR_OPEN : ViewerConstants.DOOR_CLOSED;
}
if (type == ViewerConstants.DOOR_OPEN) {
return (openCount > 0) ? items[0] : null;
} else {
return (items.length - openCount > 0) ? items[openCount] : null;
}
}
@Override
public AbstractLayerItem[] getLayerItems()
{
return items;
}
@Override
public void reload()
{
init();
}
@Override
public void update(double zoomFactor)
{
for (int i = 0; i < items.length; i++) {
items[i].setItemLocation((int)(location[i].x*zoomFactor + (zoomFactor / 2.0)),
(int)(location[i].y*zoomFactor + (zoomFactor / 2.0)));
Polygon poly = createPolygon(shapeCoords[i], zoomFactor);
normalizePolygon(poly);
items[i].setShape(poly);
}
}
@Override
public Point getMapLocation()
{
if (location.length > 0) {
return location[0];
} else {
return null;
}
}
@Override
public Point[] getMapLocations()
{
return location;
}
/**
* Returns the number of layer items for a specific open/closed state.
* @param state The state to return the number of layer items for.
* @return Number of layer items for this state.
*/
public int getLayerItemCount(int state)
{
if (state == ViewerConstants.DOOR_OPEN) {
return openCount;
} else if (state == ViewerConstants.DOOR_CLOSED) {
return items.length - openCount;
} else {
return 0;
}
}
/**
* Returns an array of layer items of the specified state.
* @param state The state of the layer items ({@code Open} or {@code Closed}).
* @return An array of layer items.
*/
public AbstractLayerItem[] getLayerItems(int state)
{
AbstractLayerItem[] retVal = new AbstractLayerItem[getLayerItemCount(state)];
if (state == ViewerConstants.DOOR_OPEN) {
System.arraycopy(items, 0, retVal, 0, getLayerItemCount(ViewerConstants.DOOR_OPEN));
} else if (state == ViewerConstants.DOOR_CLOSED) {
System.arraycopy(items, getLayerItemCount(ViewerConstants.DOOR_OPEN), retVal, 0, getLayerItemCount(ViewerConstants.DOOR_CLOSED));
}
return retVal;
}
private void init()
{
if (door != null) {
location = null;
shapeCoords = null;
String[] msg = null;
Polygon[] poly = null;
Rectangle[] bounds = null;
int count = 0;
try {
int ofsOpen = ((SectionOffset)door.getAttribute(Door.WED_DOOR_OFFSET_POLYGONS_OPEN)).getValue();
int ofsClosed = ((SectionOffset)door.getAttribute(Door.WED_DOOR_OFFSET_POLYGONS_CLOSED)).getValue();
int numOpen = ((SectionCount)door.getAttribute(Door.WED_DOOR_NUM_POLYGONS_OPEN)).getValue();
int numClosed = ((SectionCount)door.getAttribute(Door.WED_DOOR_NUM_POLYGONS_CLOSED)).getValue();
count = numOpen + numClosed;
openCount = numOpen;
location = new Point[count];
shapeCoords = new Point[count][];
msg = new String[count];
poly = new Polygon[count];
bounds = new Rectangle[count];
String[] desc = org.infinity.resource.wed.Polygon.s_flags;
// processing open door polygons
for (int i = 0; i < numOpen; i++) {
org.infinity.resource.wed.Polygon p = getPolygonStructure(door, ofsOpen, i);
if (p != null) {
String s = ((TextString)door.getAttribute(Door.WED_DOOR_NAME)).toString();
Flag flags = (Flag)p.getAttribute(org.infinity.resource.wed.Polygon.WED_POLY_FLAGS);
if (numOpen > 1) {
msg[i] = String.format("%1$s %2$d/%3$d %4$s", s, i+1, numOpen, createFlags(flags, desc));
} else {
msg[i] = String.format("%1$s %2$s", s, createFlags(flags, desc));
}
int vNum = ((SectionCount)p.getAttribute(org.infinity.resource.wed.Polygon.WED_POLY_NUM_VERTICES)).getValue();
int vOfs = ((HexNumber)getParentStructure().getAttribute(WedResource.WED_OFFSET_VERTICES)).getValue();
shapeCoords[i] = loadVertices(p, vOfs, 0, vNum, Vertex.class);
poly[i] = createPolygon(shapeCoords[i], 1.0);
bounds[i] = normalizePolygon(poly[i]);
}
}
// processing closed door polygons
for (int i = 0; i < numClosed; i++) {
org.infinity.resource.wed.Polygon p = getPolygonStructure(door, ofsClosed, i);
if (p != null) {
String s = ((TextString)door.getAttribute(Door.WED_DOOR_NAME)).toString();
Flag flags = (Flag)p.getAttribute(org.infinity.resource.wed.Polygon.WED_POLY_FLAGS);
if (numClosed > 1) {
msg[numOpen+i] = String.format("%1$s %2$d/%3$d %4$s", s, i+1, numClosed, createFlags(flags, desc));
} else {
msg[numOpen+i] = String.format("%1$s %2$s", s, createFlags(flags, desc));
}
int vNum = ((SectionCount)p.getAttribute(org.infinity.resource.wed.Polygon.WED_POLY_NUM_VERTICES)).getValue();
int vOfs = ((HexNumber)getParentStructure().getAttribute(WedResource.WED_OFFSET_VERTICES)).getValue();
shapeCoords[numOpen+i] = loadVertices(p, vOfs, 0, vNum, Vertex.class);
poly[numOpen+i] = createPolygon(shapeCoords[numOpen+i], 1.0);
bounds[numOpen+i] = normalizePolygon(poly[numOpen+i]);
}
}
} catch (Exception e) {
e.printStackTrace();
if (shapeCoords == null) {
shapeCoords = new Point[count][];
}
if (msg == null) {
msg = new String[count];
}
if (poly == null) {
poly = new Polygon[count];
}
if (bounds == null) {
bounds = new Rectangle[count];
}
}
// sanity checks
for (int i = 0; i < count; i++) {
if (shapeCoords[i] == null) {
shapeCoords[i] = new Point[0];
}
if (msg[i] == null) {
msg[i] = "";
}
if (poly[i] == null) {
poly[i] = new Polygon();
}
if (bounds[i] == null) {
bounds[i] = new Rectangle();
}
}
// creating layer items
items = new ShapedLayerItem[count];
for (int i = 0; i < count; i++) {
location[i] = new Point(bounds[i].x, bounds[i].y);
items[i] = new ShapedLayerItem(location[i], door, msg[i], poly[i]);
items[i].setName(getCategory());
items[i].setToolTipText(msg[i]);
items[i].setStrokeColor(AbstractLayerItem.ItemState.NORMAL, Color[0]);
items[i].setStrokeColor(AbstractLayerItem.ItemState.HIGHLIGHTED, Color[1]);
items[i].setFillColor(AbstractLayerItem.ItemState.NORMAL, Color[2]);
items[i].setFillColor(AbstractLayerItem.ItemState.HIGHLIGHTED, Color[3]);
items[i].setStroked(true);
items[i].setFilled(true);
items[i].setVisible(isVisible());
}
}
}
// Returns the specified WED polygon structure
private org.infinity.resource.wed.Polygon getPolygonStructure(AbstractStruct baseStruct, int baseOfs, int index)
{
// WedResource wed = (WedResource)getParentStructure();
if (baseStruct != null) {
List<StructEntry> list = baseStruct.getList();
int idx = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getOffset() >= baseOfs && list.get(i) instanceof org.infinity.resource.wed.Polygon) {
if (idx == index) {
return (org.infinity.resource.wed.Polygon)list.get(i);
}
idx++;
}
}
}
return null;
}
// Returns a flags string
private String createFlags(Flag flags, String[] desc)
{
if (flags != null) {
int numFlags = 0;
for (int i = 0; i < (flags.getSize() << 3); i++) {
if (flags.isFlagSet(i)) {
numFlags++;
}
}
if (numFlags > 0) {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < (flags.getSize() << 3); i++) {
if (flags.isFlagSet(i)) {
numFlags--;
if (desc != null && i+1 < desc.length) {
sb.append(desc[i+1]);
} else {
sb.append("Bit " + i);
}
if (numFlags > 0) {
sb.append(", ");
}
}
}
sb.append("]");
return sb.toString();
}
}
return "[No flags]";
}
}