package tinyray.language;
import java.util.Iterator;
/**
* Die Klasse PovRayCode implementiert einen Besucher (Visitor),
* der aus einem Syntaxbaum, der mit Hilfe von LanguageKit erzeugt ist,
* einen POV-Ray-Code erzeugt.
*/
public class PovRayCode implements Visitor<String, String> {
// Zeichenkette für eine neue Zeile.
private final static String NEWLINE = "\r\n";
// Zeichenkette für das Einrücken vorgesehen,
// um den Ausgabe-Code etwas lesbarer zu gestalten.
private final static String INDENT = "\t";
// Globale Parameter.
private Defaults defaults;
/**
* Initialisiert den PovRayCode-Visitor mit der Voreinstellung der
* globalen Parameter (Defaults).
*/
public PovRayCode() {
this.defaults = new Defaults();
// color = [0.5, 0.5, 0.5]
this.defaults.parameters.visitables.add(new Vector(0.5, 0.5, 0.5));
// ambient = [0.1, 0.1, 0.1]
this.defaults.parameters.visitables.add(new Vector(0.1, 0.1, 0.1));
// specular = 0.5
this.defaults.parameters.visitables.add(new Real(0.5));
// shininess = 1000.0
this.defaults.parameters.visitables.add(new Real(1000.0));
// mirror = 0.4
this.defaults.parameters.visitables.add(new Real(0.4));
}
/**
* Besucht einen besuchbaren Tinyray-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param tinyray Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Tinyray tinyray, String indent) {
String result = "";
// Kommentar
result += indent;
result += "// Automatisch generierter POV-Ray-Code (POV-Ray 3.6.1).";
result += NEWLINE + indent;
result += "// Herkunft: Tinyray (http://www.stefan-baur.de)";
result += NEWLINE;
result += NEWLINE;
// Ambience
result += NEWLINE;
result += tinyray.ambience.accept(this, indent);
result += NEWLINE;
// Camera
result += NEWLINE;
result += tinyray.camera.accept(this, indent);
result += NEWLINE;
// Background
result += NEWLINE;
result += tinyray.background.accept(this, indent);
result += NEWLINE;
// Fog
if (tinyray.fog.density.value > 0.0) {
result += NEWLINE;
result += tinyray.fog.accept(this, indent);
result += NEWLINE;
}
// Suns
Iterator<Sun> suns = tinyray.suns.iterator();
while (suns.hasNext()) {
result += NEWLINE;
result += suns.next().accept(this, indent);
result += NEWLINE;
}
// Geos
Iterator<Visitable> visitables = tinyray.visitables.iterator();
while (visitables.hasNext()) {
result += NEWLINE;
result += visitables.next().accept(this, indent);
result += NEWLINE;
}
// Sourcecode
result += NEWLINE + indent;
result += "// Quelle: Tinyray-Code";
result += NEWLINE + indent;
result += "//";
result += NEWLINE;
result += tinyray.accept(new PrettyPrint(), indent + "// ");
result += NEWLINE;
return result;
}
/**
* Besucht einen besuchbaren Camera-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param camera Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Camera camera, String indent) {
String result = "";
result += indent;
result += "camera {";
result += NEWLINE + indent + INDENT;
result += "perspective";
result += NEWLINE + indent + INDENT;
result += "location ";
result += camera.location.accept(this, "");
result += NEWLINE + indent + INDENT;
result += "look_at ";
result += camera.lookAt.accept(this, "");
result += NEWLINE + indent + INDENT;
result += "up -y";
result += NEWLINE + indent + INDENT;
result += "sky ";
result += camera.up.accept(this, "");
result += NEWLINE + indent + INDENT;
result += "angle 40.0 // eigentlich 30.0, aber 40.0 passt besser!?";
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Background-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param background Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Background background, String indent) {
String result = "";
result += indent;
result += "background {";
result += NEWLINE + indent + INDENT;
result += "color rgb ";
result += background.color.accept(this, "");
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Ambience-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param ambience Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Ambience ambience, String indent) {
String result = "";
result += indent;
result += "global_settings {";
result += NEWLINE + indent + INDENT;
result += "ambient_light rgb ";
result += ambience.color.accept(this, "");
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Fog-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param fog Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Fog fog, String indent) {
String result = "";
result += indent;
result += "fog {";
result += NEWLINE + indent + INDENT;
result += "fog_type 1";
result += NEWLINE + indent + INDENT;
Real distance = new Real(1.0 / fog.density.value);
result += "distance ";
result += distance.accept(this, "");
result += NEWLINE + indent + INDENT;
result += "color rgb ";
result += fog.color.accept(this, "");
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Sun-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param sun Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Sun sun, String indent) {
String result = "";
result += indent;
result += "light_source {";
result += NEWLINE + indent + INDENT;
Vector location = Vector.mult(10000.0, sun.direction);
result += location.accept(this, "");
result += ", ";
result += sun.color.accept(this, "");
result += NEWLINE + indent + INDENT;
result += "parallel";
result += NEWLINE + indent + INDENT;
result += "point_at ";
result += (new Vector()).accept(this, "");
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Bounding-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param bounding Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Bounding bounding, String indent) {
String result = "";
Iterator<Visitable> visitables = bounding.visitables.iterator();
while (visitables.hasNext()) {
result += NEWLINE;
result += visitables.next().accept(this, indent);
result += NEWLINE;
}
return result;
}
/**
* Besucht einen besuchbaren Triangle-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param triangle Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Triangle triangle, String indent) {
String result = "";
result += indent;
result += "triangle {";
result += NEWLINE;
result += triangle.x.accept(this, indent + INDENT);
result += ", ";
result += triangle.y.accept(this, "");
result += ", ";
result += triangle.z.accept(this, "");
result += NEWLINE;
result += triangle.parameters.accept(this, indent + INDENT);
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Sphere-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param sphere Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Sphere sphere, String indent) {
String result = "";
result += indent;
result += "sphere {";
result += NEWLINE;
result += sphere.center.accept(this, indent + INDENT);
result += ", ";
result += sphere.radius.accept(this, "");
result += NEWLINE;
result += sphere.parameters.accept(this, indent + INDENT);
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Plane-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param plane Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Plane plane, String indent) {
String result = "";
result += indent;
result += "plane {";
result += NEWLINE;
Vector normal0 = Vector.normal0(plane.x, plane.y, plane.z);
result += normal0.accept(this, indent + INDENT);
result += ", ";
Real distance = new Real(-Vector.dot(normal0, Vector.anti(plane.x)));
result += distance.accept(this, "");
result += NEWLINE;
result += plane.parameters.accept(this, indent + INDENT);
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Defaults-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param defaults Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Defaults defaults, String indent) {
String result = "";
int globalDefaultsSize = this.defaults.parameters.visitables.size();
int size = defaults.parameters.visitables.size();
for (int i = 0; i < Math.min(globalDefaultsSize, size); i++) {
Visitable v = defaults.parameters.visitables.get(i);
this.defaults.parameters.visitables.set(i, v);
}
return result;
}
/**
* Besucht einen besuchbaren Parameters-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param parameters Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Parameters parameters, String indent) {
String result = "";
int globalDefaultsSize = this.defaults.parameters.visitables.size();
int parametersSize = parameters.visitables.size();
// params auf default setzen
Parameters params = new Parameters();
for (int i = 0; i < globalDefaultsSize; i++) {
Visitable v = this.defaults.parameters.visitables.get(i);
params.visitables.add(v);
}
// params mit parameters überschreiben
for (int i = 0; i < Math.min(globalDefaultsSize, parametersSize); i++) {
Visitable v = parameters.visitables.get(i);
params.visitables.set(i, v);
}
int size = params.visitables.size();
// texture einleiten
result += indent;
result += "texture {";
if (0 < size) {
result += NEWLINE + indent + INDENT;
result += "pigment {";
result += NEWLINE + indent + INDENT + INDENT;
result += "color rgb ";
result += params.visitables.get(0).accept(this, "");
result += NEWLINE + indent + INDENT;
result += "}";
}
if (1 < size) {
// finish einleiten
result += NEWLINE + indent + INDENT;
result += "finish {";
result += NEWLINE + indent + INDENT + INDENT;
result += "ambient rgb ";
result += params.visitables.get(1).accept(this, "");
}
if (2 < size) {
result += NEWLINE + indent + INDENT + INDENT;
result += "phong ";
result += params.visitables.get(2).accept(this, "");
}
if (3 < size) {
result += NEWLINE + indent + INDENT + INDENT;
result += "phong_size ";
result += params.visitables.get(3).accept(this, "");
}
if (4 < size) {
result += NEWLINE + indent + INDENT + INDENT;
result += "reflection ";
result += params.visitables.get(4).accept(this, "");
}
if (1 < size) {
// finish abschließen
result += NEWLINE + indent + INDENT;
result += "}"; // finish
}
// texture abschließen
result += NEWLINE + indent;
result += "}";
return result;
}
/**
* Besucht einen besuchbaren Vector-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param vector Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Vector vector, String indent) {
String result = "";
result += indent;
result += "<";
result += vector.x.accept(this, "");
result += ", ";
result += vector.y.accept(this, "");
result += ", ";
result += vector.z.accept(this, "");
result += ">";
return result;
}
/**
* Besucht einen besuchbaren Real-Knoten und generiert einen
* entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
* und gibt diesen Code als Zeichenkette zurück.
* @param real Der besuchbare Knoten.
* @param indent Die Einrückung.
* @return Der generierte POV-Ray-Code.
*/
public String visit(Real real, String indent) {
String result = "";
result += indent;
result += new Float(real.value).toString();
return result;
}
}