Startseite < Informatik < Algorithmen Datenstrukturen / Software-Engineering / Programmiersprachen < Compiler Interpreter < Setty Tinyray < Tinyray-Scanner Tinyray-Parser / Tinyray-Language < Tinyray-LanguageKit Tinyray-Visitables Tinyray-Visitors < Tinyray-PrettyPrint Tinyray-DotCode Tinyray-PovRayCode [ DRUCK , 2004 , 2005 , 2006 , 2007 , 2008 , 2009 ] Tinyray-GlutCCode Tinyray-VRMLCode > > Tinyray-Raytracer / Tinyray-Wallpapers > > / Java C/C++ POV-Ray LaTeX > / Künstliche Intelligenz > Schach Privates / Inhalt >
Tinyray-GlutCCode
GlutCCode erzeugt aus einem Tinyray-Programm ein Glut/OpenGL-C-Programm.
Glut/OpenGL Über Glut/OpenGL
Zielvorstellung
Ein Tinyray-Quellprogramm soll in ein interaktives Glut/OpenGL-C-Programm übersetzt werden.
Glut ist keine Standard-Bibliothek!
Leider ist mir bei der Entwicklung vorliegenden Visitors folgendes Missgeschick unterlaufen:
  1. Ungeachtet dessen, ob nun die Glut-Bibliothek Zukunft hat oder nicht, verwendete ich dennoch diese Bibliothek, weil sie einfach gute Resultate brachte.
Vielleicht nehmen Sie sich einmal Zeit, um die Glut-Bibliothek explizit Ihren C-Bibliotheken hinzuzufügen.
Implementierung Implementierung der GlutCCode-Klasse
Die Java-Klasse GlutCCode ist hier als Visitor realisiert.
GlutCCode.java
package tinyray.language;

import java.util.Iterator;

/**
 * Die Klasse GlutCCode implementiert einen Besucher (Visitor),
 * der aus einem Syntaxbaum, der mit Hilfe von LanguageKit erzeugt ist,
 * einen Glut/OpenGL-Code in der Sprache C erzeugt.
 */

public class GlutCCode implements Visitor<String, String> {

    // Der Zeilenumbruch.
    private final static String NEWLINE = "\r\n";

    // Die Einrückung.
    private final static String INDENT = "\t";

    // Zeigt an, ob die lokalen oder die globalen Parameter
    // ausgegeben werden sollen.
    private boolean localParameters;

    // Die globalen Parameter.
    private Defaults defaults;

    // Der aktuelle Index für das parallele Sonnenlicht.
    private int lightIndex;

    /**
     * Initialisiert den GlutCCode-Besucher.
     * Die globalen Parameter werden eingestellt mit:
     *     color = [0.5, 0.5, 0.5];
     *     ambient = [0.1, 0.1, 0.1];
     *     specular = 0.5;
     *     shininess = 1000.0;
     *     mirror = 0.4 (wird aber nicht benutzt).
     */

    public GlutCCode() {
        this.localParameters = true;
        // Setzt globale Parameter
        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));
        // Setzt den Sonnenlichtindex.
        this.lightIndex = 0;
    }

    /**
     * Besucht einen besuchbaren Tinyray-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Tinyray tinyray, String indent) {
        String result = "";

        // Kommentar
        result += indent;
        result += "/*";
        result += NEWLINE + indent;
        result += " * Automatisch generierter Glut/OpenGL-C-Code.";
        result += NEWLINE + indent;
        result += " * Kompilieren unter Linux: gcc -lglut <Dateiname>";
        result += NEWLINE + indent;
        result += " * Herkunft: Tinyray (http://www.stefan-baur.de)";
        result += NEWLINE + indent;
        result += " */";
        result += NEWLINE;

        // Includes und Makros
        result += NEWLINE + indent;
        result += "#include <stdlib.h>";
        result += NEWLINE + indent;
        result += "#include <GL/glut.h>";
        result += NEWLINE;
        result += NEWLINE + indent;
        result += "#define WIDTH 600";
        result += NEWLINE + indent;
        result += "#define HEIGHT 400";
        result += NEWLINE;

        // Globale Variablen
        result += NEWLINE + indent;
        result += "// Globle Variablen für die Kamerabewegung";
        result += NEWLINE + indent;
        result += "int mousemotion = 0;";
        result += NEWLINE + indent;
        result += "int mousex = 0;";
        result += NEWLINE + indent;
        result += "int mousey = 0;";
        result += NEWLINE + indent;
        result += "GLfloat anglex = 0.0f;";
        result += NEWLINE + indent;
        result += "GLfloat angley = 0.0f;";
        result += NEWLINE;

        // Aktion Quit
        result += NEWLINE + indent;
        result += "// Programm verlassen";
        result += NEWLINE + indent;
        result += "void actionQuit()";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "exit(EXIT_SUCCESS);";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Aktion Init
        result += NEWLINE + indent;
        result += "// Initialisierung: Kameraposition";
        result += NEWLINE + indent;
        result += "void actionInit()";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "mousex = 0;";
        result += NEWLINE + indent + INDENT;
        result += "mousey = 0;";
        result += NEWLINE + indent + INDENT;
        result += "anglex = 0.0f;";
        result += NEWLINE + indent + INDENT;
        result += "angley = 0.0f;";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Aktion Licht ein/aus
        result += NEWLINE + indent;
        result += "// Licht ein/aus";
        result += NEWLINE + indent;
        result += "void actionToggleLighting()";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "if (glIsEnabled(GL_LIGHTING))";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "glDisable(GL_LIGHTING);";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent + INDENT;
        result += "else";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "glEnable(GL_LIGHTING);";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Aktion Nebel ein/aus
        result += NEWLINE + indent;
        result += "// Nebel ein/aus";
        result += NEWLINE + indent;
        result += "void actionToggleFog()";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "if (glIsEnabled(GL_FOG))";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "glDisable(GL_FOG);";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent + INDENT;
        result += "else";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "glEnable(GL_FOG);";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Aktion Shade flat/smooth
        result += NEWLINE + indent;
        result += "// Shade flat/smooth";
        result += NEWLINE + indent;
        result += "void actionToggleShadeModel()";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "int shadeModel;";
        result += NEWLINE + indent + INDENT;
        result += "glGetIntegerv(GL_SHADE_MODEL, &shadeModel);";
        result += NEWLINE;
        result += NEWLINE + indent + INDENT;
        result += "if (shadeModel == GL_SMOOTH)";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "glShadeModel(GL_FLAT);";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent + INDENT;
        result += "else";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "glShadeModel(GL_SMOOTH);";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Mouse
        result += NEWLINE + indent;
        result += "// Callback-Funktion: MouseFunc";
        result += NEWLINE + indent;
        result += "void mouse(int button, int state, int x, int y)";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "mousemotion = ";
        result += "(button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN);";
        result += NEWLINE + indent + INDENT;
        result += "if (mousemotion)";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "mousex = x;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "mousey = y;";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Motion
        result += NEWLINE + indent;
        result += "// Callback-Funktion: MotionFunc";
        result += NEWLINE + indent;
        result += "void motion(int x, int y)";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "if (mousemotion)";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "anglex += (GLfloat)(y - mousey);";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "angley += (GLfloat)(x - mousex);";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "mousex = x;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "mousey = y;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Szene erneut zeichen";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "glutPostRedisplay();";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Keyboard
        result += NEWLINE + indent;
        result += "// Callback-Funktion: KeyboardFunc";
        result += NEWLINE + indent;
        result += "void keyboard(unsigned char keyPressed, int x, int y)";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "switch (keyPressed)";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Quit";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case '0': case 'q': case 'Q': case 27:";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionQuit();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Init";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case '1': case 'i': case 'I':";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionInit();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Toggle Lighting";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case '2': case 'l': case 'L':";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionToggleLighting();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Toggle Fog";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case '3': case 'f': case 'F': case 'n': case 'N':";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionToggleFog();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Toggle ShadeModel";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case '4': case 's': case 'S':";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionToggleShadeModel();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent + INDENT;
        result += "// Szene erneut zeichen";
        result += NEWLINE + indent + INDENT;
        result += "glutPostRedisplay();";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Menu
        result += NEWLINE + indent;
        result += "// Menü-Handler";
        result += NEWLINE + indent;
        result += "void menu(int menuItem)";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "switch (menuItem)";
        result += NEWLINE + indent + INDENT;
        result += "{";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Quit";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case 0:";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionQuit();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Init";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case 1:";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionInit();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Toggle Lighting";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case 2:";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionToggleLighting();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Toggle Fog";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case 3:";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionToggleFog();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "// Toggle ShadeModel";
        result += NEWLINE + indent + INDENT + INDENT;
        result += "case 4:";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "actionToggleShadeModel();";
        result += NEWLINE + indent + INDENT + INDENT + INDENT;
        result += "break;";
        result += NEWLINE + indent + INDENT;
        result += "}";
        result += NEWLINE + indent + INDENT;
        result += "// Szene erneut zeichen";
        result += NEWLINE + indent + INDENT;
        result += "glutPostRedisplay();";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Reshape
        result += NEWLINE + indent;
        result += "// Callback-Funktion: ReshapeFunc";
        result += NEWLINE + indent;
        result += "void reshape(int width, int height)";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "glMatrixMode(GL_PROJECTION);";
        result += NEWLINE + indent + INDENT;
        result += "glLoadIdentity();";
        result += NEWLINE + indent + INDENT;
        result += "GLfloat aspect = (GLfloat)width / (GLfloat)height;";
        result += NEWLINE + indent + INDENT;
        result += "gluPerspective(30.0f, aspect, 0.1f, 1000.0f);";
        result += NEWLINE + indent + INDENT;
        result += "glViewport(0, 0, width, height);";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Display
        result += NEWLINE + indent;
        result += "// Callback-Funktion: DisplayFunc";
        result += NEWLINE + indent;
        result += "void display(void)";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "// Initialisierungen vor dem Zeichen";
        result += NEWLINE + indent + INDENT;
        result += "glMatrixMode(GL_MODELVIEW);";
        result += NEWLINE + indent + INDENT;
        result += "glLoadIdentity();";
        result += NEWLINE + indent + INDENT;
        result += "glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);";
        result += NEWLINE;
        // Background
        result += NEWLINE;
        result += tinyray.background.accept(this,  indent + INDENT);
        result += NEWLINE;
        // Fog
        result += NEWLINE;
        result += tinyray.fog.accept(this, indent + INDENT);
        result += NEWLINE;
        // Camera
        result += NEWLINE;
        result += tinyray.camera.accept(this, indent + INDENT);
        result += NEWLINE;
        result += NEWLINE + indent + INDENT;
        result += "// Rundumbewegung mit Transformationen ermöglichen";
        result += NEWLINE + indent + INDENT;
        result += "glTranslatef(";
        result += tinyray.camera.lookAt.accept(this, "");
        result += "); // <- lookAt";
        result += NEWLINE + indent + INDENT;
        result += "glRotatef(anglex, 1.0f, 0.0f, 0.0f);";
        result += NEWLINE + indent + INDENT;
        result += "glRotatef(angley, 0.0f, 1.0f, 0.0f);";
        result += NEWLINE + indent + INDENT;
        result += "glTranslatef(";
        result += Vector.anti(tinyray.camera.lookAt).accept(this, "");
        result += "); // -> lookAt";
        result += NEWLINE;
        // Ambience
        result += NEWLINE;
        result += tinyray.ambience.accept(this, indent + INDENT);
        result += NEWLINE;
        // Suns
        result += NEWLINE + indent + INDENT;
        result += "// Lichtquellen setzen";
        result += NEWLINE;
        Iterator<Sun> suns = tinyray.suns.iterator();
        while (suns.hasNext()) {
            result += NEWLINE;
            result += suns.next().accept(this, indent + INDENT);
            result += NEWLINE;
        }
        // Materialinitialisierung mit Defaults
        result += NEWLINE + indent + INDENT;
        result += "// Basismaterial";
        result += NEWLINE;
        result += this.defaults.accept(this, indent + INDENT);
        result += NEWLINE;
        // Visitables wie Geoobjekte und Defaults.
        result += NEWLINE + indent + INDENT;
        result += "// Geoobjekte setzen";
        result += NEWLINE;
        Iterator<Visitable> visitables = tinyray.visitables.iterator();
        while (visitables.hasNext()) {
            result += NEWLINE;
            result += visitables.next().accept(this, indent + INDENT);
            result += NEWLINE;
        }
        // Das neue Bild anzeigen
        result += NEWLINE + indent + INDENT;
        result += "glutSwapBuffers();";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        // Main-Methode
        result += NEWLINE + indent;
        result += "// Die Hauptfunktion";
        result += NEWLINE + indent;
        result += "int main(int argc, char* argv[])";
        result += NEWLINE + indent;
        result += "{";
        result += NEWLINE + indent + INDENT;
        result += "// Glut-Fenster";
        result += NEWLINE + indent + INDENT;
        result += "glutInit(&argc, argv);";
        result += NEWLINE + indent + INDENT;
        result += "glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);";
        result += NEWLINE + indent + INDENT;
        result += "glutInitWindowSize(WIDTH, HEIGHT);";
        result += NEWLINE + indent + INDENT;
        result += "glutInitWindowPosition(100, 100);";
        result += NEWLINE + indent + INDENT;
        result += "glutCreateWindow(argv[0]);";
        result += NEWLINE;
        result += NEWLINE + indent + INDENT;
        result += "// Ein Popup-Menu anbinden";
        result += NEWLINE + indent + INDENT;
        result += "glutCreateMenu(menu);";
        result += NEWLINE + indent + INDENT;
        result += "glutAddMenuEntry(\"Startposition\", 1);";
        result += NEWLINE + indent + INDENT;
        result += "glutAddMenuEntry(\"Lichter ein/aus\", 2);";
        result += NEWLINE + indent + INDENT;
        result += "glutAddMenuEntry(\"Nebel ein/aus\", 3);";
        result += NEWLINE + indent + INDENT;
        result += "glutAddMenuEntry(\"Shade flat/smooth\", 4);";
        result += NEWLINE + indent + INDENT;
        result += "glutAddMenuEntry(\"Programm verlassen\", 0);";
        result += NEWLINE + indent + INDENT;
        result += "glutAttachMenu(GLUT_RIGHT_BUTTON);";
        result += NEWLINE;
        result += NEWLINE + indent + INDENT;
        result += "// OpenGL-Einstellungen";
        result += NEWLINE + indent + INDENT;
        result += "glEnable(GL_LIGHTING);";
        result += NEWLINE + indent + INDENT;
        result += "glDepthFunc(GL_LESS);";
        result += NEWLINE + indent + INDENT;
        result += "glEnable(GL_DEPTH_TEST);";
        result += NEWLINE + indent + INDENT;
        result += "glEnable(GL_NORMALIZE);";
        result += NEWLINE + indent + INDENT;
        result += "glEnable(GL_FOG);";
        result += NEWLINE + indent + INDENT;
        result += "glShadeModel(GL_SMOOTH);";
        result += NEWLINE;
        result += NEWLINE + indent + INDENT;
        result += "// Zunächst Szene darstellen";
        result += NEWLINE + indent + INDENT;
        result += "reshape(WIDTH, HEIGHT);";
        result += NEWLINE + indent + INDENT;
        result += "display();";
        result += NEWLINE;
        result += NEWLINE + indent + INDENT;
        result += "// Callback-Funktionen integrieren";
        result += NEWLINE + indent + INDENT;
        result += "glutMouseFunc(mouse);";
        result += NEWLINE + indent + INDENT;
        result += "glutMotionFunc(motion);";
        result += NEWLINE + indent + INDENT;
        result += "glutKeyboardFunc(keyboard);";
        result += NEWLINE + indent + INDENT;
        result += "glutReshapeFunc(reshape);";
        result += NEWLINE + indent + INDENT;
        result += "glutDisplayFunc(display);";
        result += NEWLINE;
        result += NEWLINE + indent + INDENT;
        result += "glutMainLoop();";
        result += NEWLINE;
        result += NEWLINE + indent + INDENT;
        result += "return EXIT_SUCCESS;";
        result += NEWLINE + indent;
        result += "}";
        result += NEWLINE;

        result += NEWLINE + indent;
        result += "/* Quelle: Tinyray-Code";
        result += NEWLINE;
        result += NEWLINE;
        result += tinyray.accept(new PrettyPrint(), indent + INDENT);
        result += NEWLINE;
        result += NEWLINE + indent;
        result += "*/";
        result += NEWLINE;
        return result;
    }

    /**
     * Besucht einen besuchbaren Camera-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Camera camera, String indent) {
        String result = "";
        result += indent;
        result += "// Kamera setzen";
        result += NEWLINE + indent;
        result += "gluLookAt(";
        result += NEWLINE + indent + INDENT;
        result += camera.location.accept(this, "");
        result += ", // location";
        result += NEWLINE + indent + INDENT;
        result += camera.lookAt.accept(this, "");
        result += ", // lookAt";
        result += NEWLINE + indent + INDENT;
        result += camera.up.accept(this, "");
        result += " // up";
        result += NEWLINE + indent;
        result += ");";
        return result;
    }

    /**
     * Besucht einen besuchbaren Background-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Background background, String indent) {
        String result = "";
        result += indent;
        result += "// Hintergrundfarbe setzen";
        result += NEWLINE + indent;
        result += "glClearColor(";
        result += background.color.accept(this, "");
        result += ", 1.0f";
        result += ");";
        return result;
    }

    /**
     * Besucht einen besuchbaren Ambience-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Ambience ambience, String indent) {
        String result = "";
        result += indent;
        result += "// Globales, ambientes Umgebungslicht setzen";
        result += NEWLINE + indent;
        result += "glLightModelfv(";
        result += NEWLINE + indent + INDENT;
        result += "GL_LIGHT_MODEL_AMBIENT,";
        result += NEWLINE + indent + INDENT;
        result += "(GLfloat[]) { ";
        result += ambience.color.accept(this, "");
        result += ", 1.0f }";
        result += NEWLINE + indent;
        result += ");";
        return result;
    }

    /**
     * Besucht einen besuchbaren Fog-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Fog fog, String indent) {
        String result = "";
        result += indent;
        result += "// Nebel";
        result += NEWLINE + indent;
        result += "glFogi(GL_FOG_MODE, GL_EXP2);";
        result += NEWLINE + indent;
        result += "glFogfv(";
        result += NEWLINE + indent + INDENT;
        result += "GL_FOG_COLOR,";
        result += NEWLINE + indent + INDENT;
        result += "(GLfloat[]) { ";
        result += fog.color.accept(this, "");
        result += " }";
        result += NEWLINE + indent;
        result += ");";
        result += NEWLINE + indent;
        result += "glFogf(";
        result += NEWLINE + indent + INDENT;
        result += "GL_FOG_DENSITY,";
        result += NEWLINE + indent + INDENT;
        result += fog.density.accept(this, "");
        result += NEWLINE + indent;
        result += ");";
        return result;
    }

    /**
     * Besucht einen besuchbaren Sun-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Sun sun, String indent) {
        String result = "";
        result += indent;
        result += "// Sonne " + this.lightIndex + " setzen";
        result += NEWLINE + indent;
        // Ambienter Anteil
        result += "glLightfv(";
        result += NEWLINE + indent + INDENT;
        result += "GL_LIGHT0 + " + this.lightIndex + ",";
        result += NEWLINE + indent + INDENT;
        result += "GL_AMBIENT,";
        result += NEWLINE + indent + INDENT;
        result += "(GLfloat[]) { 0.0f, 0.0f, 0.0f, 1.0f }";
        result += NEWLINE + indent;
        result += ");";
        result += NEWLINE + indent;
        // Diffuser Anteil
        result += "glLightfv(";
        result += NEWLINE + indent + INDENT;
        result += "GL_LIGHT0 + " + this.lightIndex + ",";
        result += NEWLINE + indent + INDENT;
        result += "GL_DIFFUSE,";
        result += NEWLINE + indent + INDENT;
        result += "(GLfloat[]) { ";
        result += sun.color.accept(this, "");
        result += ", 1.0f }";
        result += NEWLINE + indent;
        result += ");";
        result += NEWLINE + indent;
        // Spekularer Anteil
        result += "glLightfv(";
        result += NEWLINE + indent + INDENT;
        result += "GL_LIGHT0 + " + this.lightIndex + ",";
        result += NEWLINE + indent + INDENT;
        result += "GL_SPECULAR,";
        result += NEWLINE + indent + INDENT;
        result += "(GLfloat[]) { ";
        result += sun.color.accept(this, "");
        result += ", 1.0f }";
        result += NEWLINE + indent;
        result += ");";
        result += NEWLINE + indent;
        // Paralleles Licht
        result += "glLightfv(";
        result += NEWLINE + indent + INDENT;
        result += "GL_LIGHT0 + " + this.lightIndex + ",";
        result += NEWLINE + indent + INDENT;
        result += "GL_POSITION,";
        result += NEWLINE + indent + INDENT;
        result += "(GLfloat[]) { ";
        result += sun.direction.accept(this, "");
        result += ", 0.0f }";
        result += NEWLINE + indent;
        result += ");";
        result += NEWLINE + indent;
        result += "glEnable(GL_LIGHT0 + " + this.lightIndex + ");";
        this.lightIndex++;
        return result;
    }

    /**
     * Besucht einen besuchbaren Bounding-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Bounding bounding, String indent) {
        String result = "";
        result += indent;
        result += "/* > Bounding */";
        result += NEWLINE;
        Iterator<Visitable> visitables = bounding.visitables.iterator();
        while (visitables.hasNext()) {
            result += NEWLINE;
            result += visitables.next().accept(this, indent + INDENT);
            result += NEWLINE;
        }
        result += NEWLINE + indent;
        result += "/* < Bounding */";
        return result;
    }

    /**
     * Besucht einen besuchbaren Triangle-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Triangle triangle, String indent) {
        String result = "";
        result += indent;
        result+= "/* > Triangle */";
        result += NEWLINE;
        this.localParameters = true;
        result += triangle.parameters.accept(this, indent);
        result += NEWLINE + indent;
        result += "glBegin(GL_TRIANGLES);";
        result += NEWLINE + indent + INDENT;
        result += "glNormal3f(";
        Vector normal = Vector.normal0(triangle.x, triangle.y, triangle.z);
        result += normal.accept(this, "");
        result += ");";
        result += NEWLINE + indent + INDENT;
        result += "glVertex3f(";
        result += triangle.x.accept(this, "");
        result += ");";
        result += NEWLINE + indent + INDENT;
        result += "glVertex3f(";
        result += triangle.y.accept(this, "");
        result += ");";
        result += NEWLINE + indent + INDENT;
        result += "glVertex3f(";
        result += triangle.z.accept(this, "");
        result += ");";
        result += NEWLINE + indent;
        result += "glEnd();";
        result += NEWLINE;
        this.localParameters = false;
        result += triangle.parameters.accept(this, indent);
        result += NEWLINE + indent;
        result+= "/* < Triangle */";
        return result;
    }

    /**
     * Besucht einen besuchbaren Sphere-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Sphere sphere, String indent) {
        String result = "";
        result += indent;
        result+= "/* > Sphere */";
        result += NEWLINE;
        this.localParameters = true;
        result += sphere.parameters.accept(this, indent);
        result += NEWLINE + indent;
        result += "glPushMatrix();";
        result += NEWLINE + indent;
        result += "glTranslatef(";
        result += sphere.center.accept(this, "");
        result += ");";
        result += NEWLINE + indent;
        result += "glutSolidSphere(";
        result += sphere.radius.accept(this, "");
        result += ", 30, 30);";
        result += NEWLINE + indent;
        result += "glPopMatrix();";
        result += NEWLINE;
        this.localParameters = false;
        result += sphere.parameters.accept(this, indent);
        result += NEWLINE + indent;
        result += "/* < Sphere */";
        return result;
    }

    /**
     * Besucht einen besuchbaren Plane-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Plane plane, String indent) {
        String result = "";
        result += indent;
        result+= "/* > Plane */";
        result += NEWLINE;
        this.localParameters = true;
        result += plane.parameters.accept(this, indent);
        result += NEWLINE + indent;
        result += "glPushMatrix();";

        // center = (p.x + p.y + p.z) / 3.0
        Vector center = new Vector();
        center.x.value = plane.x.x.value;
        center.y.value = plane.x.y.value;
        center.z.value = plane.x.z.value;
        center.x.value += plane.y.x.value;
        center.y.value += plane.y.y.value;
        center.z.value += plane.y.z.value;
        center.x.value += plane.z.x.value;
        center.y.value += plane.z.y.value;
        center.z.value += plane.z.z.value;
        center.x.value /= 3.0;
        center.y.value /= 3.0;
        center.z.value /= 3.0;

        result += NEWLINE + indent;
        result += "glTranslatef(";
        result += center.accept(this, "");
        result += ");";
        result += NEWLINE + indent;
        result += "glScalef(500.0f, 500.0f, 500.0f);";
        result += NEWLINE + indent;
        result += "glTranslatef(";
        result += Vector.anti(center).accept(this, "");
        result += ");";

        result += NEWLINE + indent;
        result += "glBegin(GL_TRIANGLES);";
        result += NEWLINE + indent + INDENT;
        result += "glNormal3f(0.0f, 0.0f, 1.0f);";
        result += NEWLINE + indent + INDENT;
        result += "glVertex3f(";
        result += plane.x.accept(this, "");
        result += ");";
        result += NEWLINE + indent + INDENT;
        result += "glVertex3f(";
        result += plane.y.accept(this, "");
        result += ");";
        result += NEWLINE + indent + INDENT;
        result += "glVertex3f(";
        result += plane.z.accept(this, "");
        result += ");";
        result += NEWLINE + indent;
        result += "glEnd();";

        result += NEWLINE + indent;
        result += "glPopMatrix();";
        result += NEWLINE;
        this.localParameters = false;
        result += plane.parameters.accept(this, indent);
        result += NEWLINE + indent;
        result+= "/* < Plane */";
        return result;
    }

    /**
     * Besucht einen besuchbaren Defaults-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Defaults defaults, String indent) {
        String result = "";

        int thisSize = this.defaults.parameters.visitables.size();
        int size = defaults.parameters.visitables.size();

        for (int i = 0; i < Math.min(thisSize, size); i++) {
            Visitable v = defaults.parameters.visitables.get(i);
            this.defaults.parameters.visitables.set(i, v);
        }

        // Die Parameter werden wieder zurückgesetzt.
        this.localParameters = false;
        result += defaults.parameters.accept(this, indent);
        return result;
    }

    /**
     * Besucht einen besuchbaren Parameters-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Parameters parameters, String indent) {
        String result = "";
        int size = parameters.visitables.size();
        result += indent;
        if (this.localParameters) {
            result += "// Parameters " + size;
        } else {
            result += "// Defaults " + size;
        }
        if (0 < size) {
            Visitable v0;
            if (this.localParameters) {
                v0 = parameters.visitables.get(0);
            } else {
                v0 = this.defaults.parameters.visitables.get(0);
            }
            result += NEWLINE + indent;
            result += "glColor3f(";
            result += v0.accept(this, "");
            result += "); // Farbe, falls Licht deaktiviert";
            result += NEWLINE + indent;
            result += "glMaterialfv(";
            result += NEWLINE + indent + INDENT;
            result += "GL_FRONT,";
            result += NEWLINE + indent + INDENT;
            result += "GL_DIFFUSE,";
            result += NEWLINE + indent + INDENT;
            result += "(GLfloat[]) { ";
            result += v0.accept(this, "");
            result += ", 1.0f }";
            result += NEWLINE + indent;
            result += ");";
        }
        if (1 < size) {
            Visitable v1;
            if (this.localParameters) {
                v1 = parameters.visitables.get(1);
            } else {
                v1 = this.defaults.parameters.visitables.get(1);
            }
            result += NEWLINE + indent;
            result += "glMaterialfv(";
            result += NEWLINE + indent + INDENT;
            result += "GL_FRONT,";
            result += NEWLINE + indent + INDENT;
            result += "GL_AMBIENT,";
            result += NEWLINE + indent + INDENT;
            result += "(GLfloat[]) { ";
            result += v1.accept(this, "");
            result += ", 1.0f }";
            result += NEWLINE + indent;
            result += ");";
        }
        if (2 < size) {
            Visitable v2;
            if (this.localParameters) {
                v2 = parameters.visitables.get(2);
            } else {
                v2 = this.defaults.parameters.visitables.get(2);
            }
            result += NEWLINE + indent;
            result += "glMaterialfv(";
            result += NEWLINE + indent + INDENT;
            result += "GL_FRONT,";
            result += NEWLINE + indent + INDENT;
            result += "GL_SPECULAR,";
            result += NEWLINE + indent + INDENT;
            result += "(GLfloat[]) { ";
            result += v2.accept(this, "");
            result += ", ";
            result += v2.accept(this, "");
            result += ", ";
            result += v2.accept(this, "");
            result += ", 1.0f }";
            result += NEWLINE + indent;
            result += ");";
        }
        if (3 < size) {
            Visitable v3;
            if (this.localParameters) {
                v3 = parameters.visitables.get(3);
            } else {
                v3 = this.defaults.parameters.visitables.get(3);
            }
            result += NEWLINE + indent;
            result += "glMaterialf(";
            result += NEWLINE + indent + INDENT;
            result += "GL_FRONT,";
            result += NEWLINE + indent + INDENT;
            result += "GL_SHININESS,";
            result += NEWLINE + indent + INDENT;
            result += v3.accept(this, "");
            result += NEWLINE + indent;
            result += ");";
        }
        if (4 < size) {
            Visitable v4;
            if (this.localParameters) {
                v4 = parameters.visitables.get(4);
            } else {
                v4 = this.defaults.parameters.visitables.get(4);
            }
            result += NEWLINE + indent;
            result += "// Mirror = ";
            result += v4.accept(this, "");
            result += " wird nicht unterstützt!";
        }
        return result;
    }

    /**
     * Besucht einen besuchbaren Vector-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Vector vector, String indent) {
        String result = "";
        result += vector.x.accept(this, indent);
        result += ", ";
        result += vector.y.accept(this, "");
        result += ", ";
        result += vector.z.accept(this, "");
        return result;
    }

    /**
     * Besucht einen besuchbaren Real-Knoten und generiert einen
     * entsprechenden Glut/OpenGL-C-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 Glut/OpenGL-C-Code.
     */

    public String visit(Real real, String indent) {
        String result = "";
        result += indent;
        result += new Float(real.value).toString(); // downcast
        result += "f";
        return result;
    }
}
Anwendung Anwendung der GlutCCode-Klasse
Folgende Anwendung nutzt die Klasse GlutCCode und wandelt ein gegebenes Tinyray-Programm in ein Glut/OpenGL-C-Programm um.
UseGlutCCode.java
package tinyray;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import tinyray.frontend.ParseException;
import tinyray.frontend.Parser;
import tinyray.frontend.Scanner;
import tinyray.language.GlutCCode;
import tinyray.language.LanguageKit;
import tinyray.language.Tinyray;
import tinyray.language.Visitable;

/**
 * Die Klasse UseGlutCCode generiert aus einem Tinyray-Code
 * einen entsprechenden C-Code mit Hilfe der GLUT/OpenGL-Bibliothek
 * (siehe http://www.opengl.org/).
 */

public class UseGlutCCode {

    /**
     * Das Hauptprogramm, welches aus einem Tinyray-Code einen entsprechenden
     * Glut-C-Code generiert.
     * Das Ergebnis wird auf der Konsole ausgegeben (System.out).
     * @param arguments Die Aufrufargumente.
     *        Das erste Argument gibt den Dateinamen der Tinyray-Datei an.
     *        Ist das erste Argument nicht gesetzt, erhält der Benutzer
     *        einen kurzen Hilfetext.
     */

    public static void main(String[] arguments) {

        // Mindestens ein Argument erforderlich: <Dateiname>
        if (arguments.length > 0) {

            try {
                // Der Scanner erhält den Tinyray-Code als Stream.
                Scanner scanner =
                    new Scanner(new FileInputStream(arguments[0]));

                // Der Parser erhält den Scanner und eine konkreten Fabrik
                // (hier LanguageKit).
                Parser<Visitable, Tinyray> parser =
                    new Parser<Visitable, Tinyray>(scanner, new LanguageKit());

                // Der Parse-Vorgang bringt einen Syntaxbaum hervor.
                // Die einzelnen Knoten des Syntaxbaumes werden automatisch
                // von der konkreten Fabrik "LanguageKit" erzeugt.
                Tinyray tinyray = parser.parse();

                // Der Syntaxbaum besteht aus besuchbaren Knoten (accept).
                // GlutCCode ist ein Besucher, der die Wurzel des
                // Syntaxbaums besucht und dabei einen entsprechenden
                // Glut/OpenGL-C-Code (glutccode) generiert.
                String glutccode = tinyray.accept(new GlutCCode(), "");

                // Ausgabe des generierten Glut-C-Codes.
                System.out.println(glutccode);

            } catch (ParseException e) {
                // Fehlermeldung, falls gegebener Tinyray-Code fehlerhaft.
                System.err.println(e.getMessage());
            } catch (FileNotFoundException e) {
                // Fehlermeldung, falls das erste Argument keine Datei benennt.
                System.err.println(e.getMessage());
            }

        } else {
            // Kurzhilfe, falls Aufruf ohne Argument.
            System.out.println(usage());
        }
    }

    /**
     * Erläuterung zum korrekten Aufruf (Kurzhilfe).
     * @return Die Kurzhilfe als Zeichenkette.
     */

    public static String usage() {
        String result = "";
        result += "java tinyray/UseGlutCCode <TinyrayDatei>\r\n";
        result += "\r\nBeispiele:\r\n";
        result += " java tinyray/UseGlutCCode MyScene.tinyray\r\n";
        result += " java tinyray/UseGlutCCode Test01.txt\r\n";
        result += "\r\nHinweis:\r\n";
        result += " Mindestens JRE (java-1.6.0) erforderlich.\r\n";
        return result;
    }
}
Ein Programmaufruf ohne Aufrufparameter zeigt dem Aufrufenden die Programmkurzhilfe (usage).
java UseGlutCCode
java tinyray/UseGlutCCode <TinyrayDatei>

Beispiele:
 java tinyray/UseGlutCCode MyScene.tinyray
 java tinyray/UseGlutCCode Test01.txt

Hinweis:
 Mindestens JRE (java-1.5.0) erforderlich.