package org.osm2world.core.target.common;
import static java.util.Arrays.asList;
import static java.util.Collections.*;
import static org.osm2world.core.math.GeometryUtil.*;
import static org.osm2world.core.target.common.material.NamedTexCoordFunction.*;
import static org.osm2world.core.target.common.material.TexCoordUtil.texCoordLists;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.configuration.Configuration;
import org.osm2world.core.math.VectorXYZ;
import org.osm2world.core.math.VectorXZ;
import org.osm2world.core.target.Renderable;
import org.osm2world.core.target.Target;
import org.osm2world.core.target.common.material.Material;
import org.osm2world.core.world.data.WorldObject;
/**
* superclass for {@link Target} implementations that defines some
* of the required methods using others. Extending it reduces the number of
* methods that have to be provided by the implementation
*/
public abstract class AbstractTarget<R extends Renderable>
implements Target<R> {
protected Configuration config;
@Override
public void setConfiguration(Configuration config) {
this.config = config;
}
@Override
public void beginObject(WorldObject object) {}
@Override
public void drawBox(Material material,
VectorXYZ bottomCenter, VectorXZ faceDirection,
double height, double width, double depth) {
final VectorXYZ backVector = faceDirection.mult(-depth).xyz(0);
final VectorXYZ rightVector = faceDirection.rightNormal().mult(-width).xyz(0);
final VectorXYZ upVector = new VectorXYZ(0, height, 0);
final VectorXYZ frontLowerLeft = bottomCenter
.add(rightVector.mult(-0.5))
.add(backVector.mult(-0.5));
final VectorXYZ frontLowerRight = frontLowerLeft.add(rightVector);
final VectorXYZ frontUpperLeft = frontLowerLeft.add(upVector);
final VectorXYZ frontUpperRight = frontLowerRight.add(upVector);
final VectorXYZ backLowerLeft = frontLowerLeft.add(backVector);
final VectorXYZ backLowerRight = frontLowerRight.add(backVector);
final VectorXYZ backUpperLeft = frontUpperLeft.add(backVector);
final VectorXYZ backUpperRight = frontUpperRight.add(backVector);
List<VectorXYZ> vsStrip1 = asList(
backLowerLeft, backLowerRight,
frontLowerLeft, frontLowerRight,
frontUpperLeft, frontUpperRight,
backUpperLeft, backUpperRight
);
List<VectorXYZ> vsStrip2 = asList(
frontUpperRight, frontLowerRight,
backUpperRight, backLowerRight,
backUpperLeft, backLowerLeft,
frontUpperLeft, frontLowerLeft
);
List<List<VectorXZ>> texCoords1 = null, texCoords2 = null;
if (material.getTextureDataList() != null) {
texCoords1 = nCopies(material.getTextureDataList().size(), BOX_TEX_COORDS_1);
texCoords2 = nCopies(material.getTextureDataList().size(), BOX_TEX_COORDS_2);
}
drawTriangleStrip(material, vsStrip1, texCoords1);
drawTriangleStrip(material, vsStrip2, texCoords2);
}
protected static final List<VectorXZ> BOX_TEX_COORDS_1 = asList(
new VectorXZ(0, 0), new VectorXZ(0.25, 0),
new VectorXZ(0, 1.0/3), new VectorXZ(0.25, 1.0/3),
new VectorXZ(0, 2.0/3), new VectorXZ(0.25, 2.0/3),
new VectorXZ(0, 1), new VectorXZ(0.25, 1)
);
protected static final List<VectorXZ> BOX_TEX_COORDS_2 = asList(
new VectorXZ(0.25, 2.0/3), new VectorXZ(0.25, 1.0/3),
new VectorXZ(0.50, 2.0/3), new VectorXZ(0.50, 1.0/3),
new VectorXZ(0.75, 2.0/3), new VectorXZ(0.75, 1.0/3),
new VectorXZ(1.00, 2.0/3), new VectorXZ(1.00, 1.0/3)
);
private static final int EDGES_FOR_CYLINDER = 16;
@Override
public void drawColumn(Material material, Integer corners, VectorXYZ base,
double height, double radiusBottom, double radiusTop,
boolean drawBottom, boolean drawTop) {
if (corners == null) {
corners = EDGES_FOR_CYLINDER;
material = material.makeSmooth();
}
float angleInterval = (float) (2 * Math.PI / corners);
/* prepare vector lists for the 3 primitives */
List<VectorXYZ> bottomFan = new ArrayList<VectorXYZ>(corners + 2);
List<VectorXYZ> topFan = new ArrayList<VectorXYZ>(corners + 2);
List<VectorXYZ> mantleStrip = new ArrayList<VectorXYZ>(corners + 2);
/* fill vectors into lists */
bottomFan.add(base);
topFan.add(base.add(0, height, 0));
for (int i = 0; i <= corners; i++) {
double angle = - i * angleInterval;
double sin = Math.sin(angle);
double cos = Math.cos(angle);
VectorXYZ topV = base.add(
radiusTop * sin, height, radiusTop * cos);
VectorXYZ bottomV = base.add(
radiusBottom * sin, 0, radiusBottom * cos);
bottomFan.add(bottomV);
topFan.add(topV);
mantleStrip.add(topV);
mantleStrip.add(bottomV);
}
Collections.reverse(bottomFan);
/* draw the 3 primitives */
if (drawBottom) { drawTriangleFan(material, bottomFan,
texCoordLists(bottomFan, material, GLOBAL_X_Z)); }
if (drawTop) { drawTriangleFan(material, topFan,
texCoordLists(bottomFan, material, GLOBAL_X_Z)); }
drawTriangleStrip(material, mantleStrip,
texCoordLists(mantleStrip, material, STRIP_WALL));
}
@Override
public void drawTriangleStrip(Material material, List<VectorXYZ> vs,
List<List<VectorXZ>> texCoordLists) {
List<List<VectorXZ>> newTexCoordLists = emptyList();
if (texCoordLists != null && !texCoordLists.isEmpty()) {
newTexCoordLists = new ArrayList<List<VectorXZ>>(texCoordLists.size());
for (List<VectorXZ> texCoordList : texCoordLists) {
newTexCoordLists.add(
triangleVertexListFromTriangleStrip(texCoordList));
}
}
drawTriangles(material, trianglesFromTriangleStrip(vs), newTexCoordLists);
}
@Override
public void drawTriangleFan(Material material, List<VectorXYZ> vs,
List<List<VectorXZ>> texCoordLists) {
List<List<VectorXZ>> newTexCoordLists = emptyList();
if (texCoordLists != null && !texCoordLists.isEmpty()) {
newTexCoordLists = new ArrayList<List<VectorXZ>>(texCoordLists.size());
for (List<VectorXZ> texCoordList : texCoordLists) {
newTexCoordLists.add(
triangleVertexListFromTriangleFan(texCoordList));
}
}
drawTriangles(material, trianglesFromTriangleFan(vs), newTexCoordLists);
}
@Override
public void drawConvexPolygon(Material material, List<VectorXYZ> vs,
List<List<VectorXZ>> texCoordLists) {
drawTriangleFan(material, vs, texCoordLists);
}
@Override
public void finish() {}
}