Initial revision
[lsystem3d.git] / src / openglwindow.cpp
diff --git a/src/openglwindow.cpp b/src/openglwindow.cpp
new file mode 100644 (file)
index 0000000..ba5c753
--- /dev/null
@@ -0,0 +1,391 @@
+// Copyright (C) 2006 Erik Dahlberg
+// 
+// This file is part of LSystem3d.
+// 
+// LSystem3D is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+// 
+// LSystem3D is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with LSystem3D; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+
+
+#include <string>
+
+#include <glui.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/freeglut.h>
+
+#include "callbacks.h"
+#include "lindenmayersystem.h"
+#include "lsystemparameters.h"
+#include "model.h"
+#include "openglwindow.h"
+
+using namespace std;
+
+extern OpenGLWindow *openglWindow;
+
+
+
+/**
+ * Constructor
+ */
+OpenGLWindow::OpenGLWindow()
+{
+    // misc init
+    
+    openglWindow = this;
+    _busyGenerating = true;
+    lsystemParametersPath = "lsystem.xml";
+    defaultView();
+
+        
+    
+    // init GLUT & GLUI
+    // ----------------
+     
+    // drawing window
+    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+    glutInitWindowSize(800, 800); 
+    int _window = glutCreateWindow("lsystem");
+     
+    // return control after closing the window
+    glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, 1);
+     
+    // register callbacks
+    glutKeyboardFunc(glutKeyboardCB);
+    glutSpecialFunc(glutSpecialCB);
+    glutDisplayFunc(glutDisplayCB);
+    GLUI_Master.set_glutIdleFunc(glutIdleCB);
+    
+    // GUI window
+    _glui = GLUI_Master.create_glui("lsystem");
+    
+    // model and l-system creation
+    _model = new Model;
+    _lsystem = new LindenmayerSystem(_model);
+    
+    // load lsystem parameters
+    _lsystemParameters.load(_lsystem, lsystemParametersPath.c_str());
+    
+    
+    
+    // create GLUI widgets
+    // -------------------
+    
+    // axiom
+    _axiomEditText = _glui->add_edittext("Axiom", GLUI_EDITTEXT_TEXT);
+    _axiomEditText->set_text((char *)_lsystem->getAxiom().c_str());
+    
+    // rules
+    // TODO: make dynamic!
+    GLUI_Panel *panel = _glui->add_panel("Rules", GLUI_PANEL_EMBOSSED);
+    _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#1", GLUI_EDITTEXT_TEXT));
+    _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#2", GLUI_EDITTEXT_TEXT));
+    _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#3", GLUI_EDITTEXT_TEXT));
+    _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#4", GLUI_EDITTEXT_TEXT));
+    _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#5", GLUI_EDITTEXT_TEXT));
+    _ruleEditTexts[0]->set_w(200);
+    _ruleEditTexts[1]->set_w(200);
+    _ruleEditTexts[2]->set_w(200);
+    _ruleEditTexts[3]->set_w(200);
+    _ruleEditTexts[4]->set_w(200);
+    
+    // sync gui and l-system
+    map<string,string> rules = _lsystem->getRules();
+    map<string,string>::iterator currentRule;
+    int i = 0;
+    for (currentRule = rules.begin(); currentRule != rules.end(); currentRule++)
+    {
+        string rule = currentRule->first + "=" + currentRule->second;
+        // TODO: bounds?
+        _ruleEditTexts[i++]->set_text((char *)rule.c_str());
+    }
+    
+    // angle
+    _angleSpinner = _glui->add_spinner("Angle", GLUI_SPINNER_FLOAT, NULL, -1, (GLUI_Update_CB)gluiSpinnerAngleCB);
+    _angleSpinner->set_float_val(_lsystem->getAngle());
+    _angleSpinner->set_speed(1.0);
+    
+    // iterations
+    _iterationsSpinner = _glui->add_spinner("Iterations", GLUI_SPINNER_INT);
+    _iterationsSpinner->set_int_val(_lsystem->getNumIterations());
+    
+    
+    _glui->add_separator();
+    
+    
+    // live update
+    _liveUpdates = 1;
+    _liveCheckbox = _glui->add_checkbox("Live update", &_liveUpdates);
+    
+    // reset
+    _glui->add_button("Reset view", -1, (GLUI_Update_CB)gluiButtonResetCB);
+    
+    // generate
+    _glui->add_button("Generate", -1, (GLUI_Update_CB)gluiButtonGenerateCB);
+    
+    
+    _glui->set_main_gfx_window(_window);
+    
+     
+
+    
+    // init OpenGL view
+    // ----------------
+
+    // projection
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(65, 1, 1, 100);
+
+    // model view
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    gluLookAt(0.0, 0.0, 2.0,
+              0.0, 0.0, 0.0,
+              0.0, 1.0, 0.0);
+
+    glClearColor(0.0, 0.0, 0.0, 0.0);
+    
+    glShadeModel(GL_SMOOTH);
+
+    // light
+    GLfloat lightPosition[] = {0.0, 0.0, 2.0, 0.0};
+    GLfloat white[] = {1.0, 1.0, 1.0, 1.0};
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
+    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
+    
+    glEnable(GL_COLOR_MATERIAL);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+    glEnable(GL_DEPTH_TEST);
+
+    glutMainLoop();
+}
+
+
+
+/**
+ * Destructor
+ */
+OpenGLWindow::~OpenGLWindow()
+{
+    // save current l-system to disk
+    _lsystemParameters.save(_lsystem, lsystemParametersPath.c_str());
+    
+    delete _lsystem;
+    delete _model;
+}
+
+
+
+/**
+ * Start generation of l-system data
+ */
+void OpenGLWindow::generate()
+{   
+    _busyGenerating = true;
+    
+        // read GLUI widgets and set corresponding l-system parameters
+    
+        // axiom
+        char *axiom = _axiomEditText->get_text();
+        _lsystem->setAxiom(axiom);
+        
+        // rules
+        vector<char *> rules;
+        rules.push_back(_ruleEditTexts[0]->get_text());
+        rules.push_back(_ruleEditTexts[1]->get_text());
+        rules.push_back(_ruleEditTexts[2]->get_text());
+        rules.push_back(_ruleEditTexts[3]->get_text());
+        rules.push_back(_ruleEditTexts[4]->get_text());
+        
+        for (int i = 0; i < rules.size(); i++)
+        {
+            if (rules[i][0] != '\0')
+            {
+                // non-empty rule
+
+                // separate rule name from the actual rule
+                string ruleName(rules[i], 1);
+                string theRule(rules[i]+2);
+                
+                _lsystem->setRule(ruleName, theRule);
+            }
+        }
+        
+        // angle
+        float angle = _angleSpinner->get_float_val();
+        _lsystem->setAngle(angle);
+        
+        // iterations
+        int iterations = _iterationsSpinner->get_int_val();
+        _lsystem->setNumIterations(iterations);
+
+        
+        // start generation
+        _model->begin();
+        _lsystem->generate();
+        _model->end();
+    
+    _busyGenerating = false;
+}
+
+
+
+/**
+ * Move camera left
+ */
+void OpenGLWindow::left()
+{
+    _xModel += 0.1;
+    glutPostRedisplay();
+}
+
+
+
+/**
+ * Move camera right
+ */
+void OpenGLWindow::right()
+{
+    _xModel -= 0.1;
+    glutPostRedisplay();
+}
+    
+    
+
+/**
+ * Move camera up
+ */
+void OpenGLWindow::up()
+{
+    _yModel -= 0.1;
+    glutPostRedisplay();
+}
+
+
+    
+/**
+ * Move camera down
+ */
+void OpenGLWindow::down()
+{
+    _yModel += 0.1;
+    glutPostRedisplay();
+}
+
+
+
+/**
+ * Move camera forth
+ */
+void OpenGLWindow::forth()
+{
+    _zModel += 1;
+    glutPostRedisplay();
+}
+
+
+
+/**
+ * Move camera back
+ */
+void OpenGLWindow::back()
+{
+    _zModel -= 1;
+    glutPostRedisplay();
+}
+
+
+
+/**
+ * Zoom in
+ */
+void OpenGLWindow::zoomIn()
+{
+    _scaleModel *= 1.1;
+    glutPostRedisplay();
+}
+
+
+
+/**
+ * Zoom out
+ */
+void OpenGLWindow::zoomOut()
+{
+     _scaleModel /= 1.1;
+    glutPostRedisplay();
+}
+
+
+
+/**
+ * Rotate around y-axis
+ */
+void OpenGLWindow::rotateY()
+{
+    _yRotationModel = int(_yRotationModel + 5.0) % 360;
+    glutPostRedisplay();
+}
+
+
+
+/**
+ * Draw l-system model to screen
+ */
+void OpenGLWindow::draw()
+{
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    
+    if (!_busyGenerating)
+    {
+        // ready for rendering
+        
+        glPushMatrix();
+            glTranslatef(_xModel, _yModel, _zModel);
+            glScalef(_scaleModel, _scaleModel, _scaleModel);
+            glRotatef(_yRotationModel, 0.0, 1.0, 0.0);
+            
+            _model->draw();
+        glPopMatrix();
+    }
+    
+    glutSwapBuffers();
+}
+
+
+
+/**
+ * Reset to default view
+ */
+void OpenGLWindow::defaultView()
+{
+    _xModel = _yModel = _zModel = 0.0;
+    _scaleModel = 1.0;
+    _yRotationModel = 0.0;
+}
+
+
+
+/**
+ * Check if live mode is activated
+ * @return true, if activated
+ */
+bool OpenGLWindow::liveActivated()
+{
+    return _liveUpdates;
+}