package org.osm2world.core.target.statistics; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.osm2world.core.math.VectorXYZ; import org.osm2world.core.math.VectorXZ; import org.osm2world.core.target.common.PrimitiveTarget; import org.osm2world.core.target.common.RenderableToPrimitiveTarget; import org.osm2world.core.target.common.Primitive.Type; import org.osm2world.core.target.common.material.Material; import org.osm2world.core.target.jogl.JOGLRendererVBO; import org.osm2world.core.world.data.WorldObject; /** * a target that simply counts the primitives that are sent to it * to create statistics. */ public class StatisticsTarget extends PrimitiveTarget<RenderableToPrimitiveTarget> { private long[] globalCounts = new long[Stat.values().length]; private Map<Material, long[]> countsPerMaterial = new HashMap<Material, long[]>(); private Map<Class<?>, long[]> countsPerClass = new HashMap<Class<?>, long[]>(); private WorldObject currentObject = null; private static abstract class StatImpl { public long countObject(WorldObject object) { return 0; } public long countPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { return 0; } } public static enum Stat { OBJECT_COUNT(new StatImpl() { @Override public long countObject(WorldObject object) { return 1; } }), PRIMITIVE_COUNT(new StatImpl() { @Override public long countPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { return 1; } }), TOTAL_TRIANGLE_COUNT(new StatImpl() { @Override public long countPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { if (type == Type.TRIANGLES) { return vs.size() / 3; } else { return vs.size() - 2; } } }), TRIANGLES_COUNT(new StatImpl() { @Override public long countPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { return type == Type.TRIANGLES ? 1 : 0; } }), TRIANGLE_STRIP_COUNT(new StatImpl() { @Override public long countPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { return type == Type.TRIANGLE_STRIP ? 1 : 0; } }), TRIANGLE_FAN_COUNT(new StatImpl() { @Override public long countPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { return type == Type.TRIANGLE_FAN ? 1 : 0; } }), CONVEX_POLYGON_COUNT(new StatImpl() { @Override public long countPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { return type == Type.CONVEX_POLYGON ? 1 : 0; } }), VBO_VALUE_COUNT(new StatImpl() { @Override public long countPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { int vertexCount; if (type == Type.TRIANGLES) { vertexCount = vs.size(); } else { vertexCount = 3 * (vs.size() - 2); } return vertexCount * JOGLRendererVBO.getValuesPerVertex(material); } }); private final StatImpl impl; private Stat(StatImpl impl) { this.impl = impl; } } @Override public Class<RenderableToPrimitiveTarget> getRenderableType() { return RenderableToPrimitiveTarget.class; } @Override public void render(RenderableToPrimitiveTarget renderable) { renderable.renderTo(this); } @Override public void beginObject(WorldObject object) { currentObject = object; if (currentObject != null) { Class<?> currentClass = currentObject.getClass(); if (!countsPerClass.containsKey(currentClass)) { countsPerClass.put(currentClass, new long[Stat.values().length]); } for (Stat stat : Stat.values()) { long count = stat.impl.countObject(object); globalCounts[stat.ordinal()] += count; if (currentObject != null) { countsPerClass.get(currentClass)[stat.ordinal()] += count; } } } super.beginObject(object); } @Override protected void drawPrimitive(Type type, Material material, List<VectorXYZ> vs, List<VectorXYZ> normals, List<List<VectorXZ>> texCoordLists) { if (!countsPerMaterial.containsKey(material)) { countsPerMaterial.put(material, new long[Stat.values().length]); } for (Stat stat : Stat.values()) { long count = stat.impl.countPrimitive( type, material, vs, normals, texCoordLists); globalCounts[stat.ordinal()] += count; if (material != null) { countsPerMaterial.get(material)[stat.ordinal()] += count; } if (currentObject != null) { countsPerClass.get(currentObject.getClass())[stat.ordinal()] += count; } } } public void clear() { for (int i=0; i < globalCounts.length; ++i) { globalCounts[i] = 0; } countsPerMaterial.clear(); countsPerClass.clear(); currentObject = null; } public long getGlobalCount(Stat stat) { return globalCounts[stat.ordinal()]; } public Set<Material> getKnownMaterials() { return countsPerMaterial.keySet(); } public long getCountForMaterial(Material material, Stat stat) { return countsPerMaterial.get(material)[stat.ordinal()]; } public Set<Class<?>> getKnownRenderableClasses() { return countsPerClass.keySet(); } public long getCountForClass(Class<?> c, Stat stat) { return countsPerClass.get(c)[stat.ordinal()]; } }