Initial revision
[lsystem3d.git] / lsystem3d / src / openglwindow.cpp
1 // Copyright (C) 2006 Erik Dahlberg
2 //
3 // This file is part of LSystem3d.
4 //
5 // LSystem3D is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // LSystem3D is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with LSystem3D; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
20
21
22 #include <string>
23
24 #include <glui.h>
25 #include <GL/gl.h>
26 #include <GL/glu.h>
27 #include <GL/freeglut.h>
28
29 #include "callbacks.h"
30 #include "lindenmayersystem.h"
31 #include "lsystemparameters.h"
32 #include "model.h"
33 #include "openglwindow.h"
34
35 using namespace std;
36
37 extern OpenGLWindow *openglWindow;
38
39
40
41 /**
42 * Constructor
43 */
44 OpenGLWindow::OpenGLWindow()
45 {
46 // misc init
47
48 openglWindow = this;
49 _busyGenerating = true;
50 lsystemParametersPath = "lsystem.xml";
51 defaultView();
52
53
54
55 // init GLUT & GLUI
56 // ----------------
57
58 // drawing window
59 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
60 glutInitWindowSize(800, 800);
61 int _window = glutCreateWindow("lsystem");
62
63 // return control after closing the window
64 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, 1);
65
66 // register callbacks
67 glutKeyboardFunc(glutKeyboardCB);
68 glutSpecialFunc(glutSpecialCB);
69 glutDisplayFunc(glutDisplayCB);
70 GLUI_Master.set_glutIdleFunc(glutIdleCB);
71
72 // GUI window
73 _glui = GLUI_Master.create_glui("lsystem");
74
75 // model and l-system creation
76 _model = new Model;
77 _lsystem = new LindenmayerSystem(_model);
78
79 // load lsystem parameters
80 _lsystemParameters.load(_lsystem, lsystemParametersPath.c_str());
81
82
83
84 // create GLUI widgets
85 // -------------------
86
87 // axiom
88 _axiomEditText = _glui->add_edittext("Axiom", GLUI_EDITTEXT_TEXT);
89 _axiomEditText->set_text((char *)_lsystem->getAxiom().c_str());
90
91 // rules
92 // TODO: make dynamic!
93 GLUI_Panel *panel = _glui->add_panel("Rules", GLUI_PANEL_EMBOSSED);
94 _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#1", GLUI_EDITTEXT_TEXT));
95 _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#2", GLUI_EDITTEXT_TEXT));
96 _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#3", GLUI_EDITTEXT_TEXT));
97 _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#4", GLUI_EDITTEXT_TEXT));
98 _ruleEditTexts.push_back(_glui->add_edittext_to_panel(panel, "#5", GLUI_EDITTEXT_TEXT));
99 _ruleEditTexts[0]->set_w(200);
100 _ruleEditTexts[1]->set_w(200);
101 _ruleEditTexts[2]->set_w(200);
102 _ruleEditTexts[3]->set_w(200);
103 _ruleEditTexts[4]->set_w(200);
104
105 // sync gui and l-system
106 map<string,string> rules = _lsystem->getRules();
107 map<string,string>::iterator currentRule;
108 int i = 0;
109 for (currentRule = rules.begin(); currentRule != rules.end(); currentRule++)
110 {
111 string rule = currentRule->first + "=" + currentRule->second;
112 // TODO: bounds?
113 _ruleEditTexts[i++]->set_text((char *)rule.c_str());
114 }
115
116 // angle
117 _angleSpinner = _glui->add_spinner("Angle", GLUI_SPINNER_FLOAT, NULL, -1, (GLUI_Update_CB)gluiSpinnerAngleCB);
118 _angleSpinner->set_float_val(_lsystem->getAngle());
119 _angleSpinner->set_speed(1.0);
120
121 // iterations
122 _iterationsSpinner = _glui->add_spinner("Iterations", GLUI_SPINNER_INT);
123 _iterationsSpinner->set_int_val(_lsystem->getNumIterations());
124
125
126 _glui->add_separator();
127
128
129 // live update
130 _liveUpdates = 1;
131 _liveCheckbox = _glui->add_checkbox("Live update", &_liveUpdates);
132
133 // reset
134 _glui->add_button("Reset view", -1, (GLUI_Update_CB)gluiButtonResetCB);
135
136 // generate
137 _glui->add_button("Generate", -1, (GLUI_Update_CB)gluiButtonGenerateCB);
138
139
140 _glui->set_main_gfx_window(_window);
141
142
143
144
145 // init OpenGL view
146 // ----------------
147
148 // projection
149 glMatrixMode(GL_PROJECTION);
150 glLoadIdentity();
151 gluPerspective(65, 1, 1, 100);
152
153 // model view
154 glMatrixMode(GL_MODELVIEW);
155 glLoadIdentity();
156 gluLookAt(0.0, 0.0, 2.0,
157 0.0, 0.0, 0.0,
158 0.0, 1.0, 0.0);
159
160 glClearColor(0.0, 0.0, 0.0, 0.0);
161
162 glShadeModel(GL_SMOOTH);
163
164 // light
165 GLfloat lightPosition[] = {0.0, 0.0, 2.0, 0.0};
166 GLfloat white[] = {1.0, 1.0, 1.0, 1.0};
167 glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
168 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
169
170 glEnable(GL_COLOR_MATERIAL);
171 glEnable(GL_LIGHTING);
172 glEnable(GL_LIGHT0);
173 glEnable(GL_DEPTH_TEST);
174
175 glutMainLoop();
176 }
177
178
179
180 /**
181 * Destructor
182 */
183 OpenGLWindow::~OpenGLWindow()
184 {
185 // save current l-system to disk
186 _lsystemParameters.save(_lsystem, lsystemParametersPath.c_str());
187
188 delete _lsystem;
189 delete _model;
190 }
191
192
193
194 /**
195 * Start generation of l-system data
196 */
197 void OpenGLWindow::generate()
198 {
199 _busyGenerating = true;
200
201 // read GLUI widgets and set corresponding l-system parameters
202
203 // axiom
204 char *axiom = _axiomEditText->get_text();
205 _lsystem->setAxiom(axiom);
206
207 // rules
208 vector<char *> rules;
209 rules.push_back(_ruleEditTexts[0]->get_text());
210 rules.push_back(_ruleEditTexts[1]->get_text());
211 rules.push_back(_ruleEditTexts[2]->get_text());
212 rules.push_back(_ruleEditTexts[3]->get_text());
213 rules.push_back(_ruleEditTexts[4]->get_text());
214
215 for (int i = 0; i < rules.size(); i++)
216 {
217 if (rules[i][0] != '\0')
218 {
219 // non-empty rule
220
221 // separate rule name from the actual rule
222 string ruleName(rules[i], 1);
223 string theRule(rules[i]+2);
224
225 _lsystem->setRule(ruleName, theRule);
226 }
227 }
228
229 // angle
230 float angle = _angleSpinner->get_float_val();
231 _lsystem->setAngle(angle);
232
233 // iterations
234 int iterations = _iterationsSpinner->get_int_val();
235 _lsystem->setNumIterations(iterations);
236
237
238 // start generation
239 _model->begin();
240 _lsystem->generate();
241 _model->end();
242
243 _busyGenerating = false;
244 }
245
246
247
248 /**
249 * Move camera left
250 */
251 void OpenGLWindow::left()
252 {
253 _xModel += 0.1;
254 glutPostRedisplay();
255 }
256
257
258
259 /**
260 * Move camera right
261 */
262 void OpenGLWindow::right()
263 {
264 _xModel -= 0.1;
265 glutPostRedisplay();
266 }
267
268
269
270 /**
271 * Move camera up
272 */
273 void OpenGLWindow::up()
274 {
275 _yModel -= 0.1;
276 glutPostRedisplay();
277 }
278
279
280
281 /**
282 * Move camera down
283 */
284 void OpenGLWindow::down()
285 {
286 _yModel += 0.1;
287 glutPostRedisplay();
288 }
289
290
291
292 /**
293 * Move camera forth
294 */
295 void OpenGLWindow::forth()
296 {
297 _zModel += 1;
298 glutPostRedisplay();
299 }
300
301
302
303 /**
304 * Move camera back
305 */
306 void OpenGLWindow::back()
307 {
308 _zModel -= 1;
309 glutPostRedisplay();
310 }
311
312
313
314 /**
315 * Zoom in
316 */
317 void OpenGLWindow::zoomIn()
318 {
319 _scaleModel *= 1.1;
320 glutPostRedisplay();
321 }
322
323
324
325 /**
326 * Zoom out
327 */
328 void OpenGLWindow::zoomOut()
329 {
330 _scaleModel /= 1.1;
331 glutPostRedisplay();
332 }
333
334
335
336 /**
337 * Rotate around y-axis
338 */
339 void OpenGLWindow::rotateY()
340 {
341 _yRotationModel = int(_yRotationModel + 5.0) % 360;
342 glutPostRedisplay();
343 }
344
345
346
347 /**
348 * Draw l-system model to screen
349 */
350 void OpenGLWindow::draw()
351 {
352 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
353
354 if (!_busyGenerating)
355 {
356 // ready for rendering
357
358 glPushMatrix();
359 glTranslatef(_xModel, _yModel, _zModel);
360 glScalef(_scaleModel, _scaleModel, _scaleModel);
361 glRotatef(_yRotationModel, 0.0, 1.0, 0.0);
362
363 _model->draw();
364 glPopMatrix();
365 }
366
367 glutSwapBuffers();
368 }
369
370
371
372 /**
373 * Reset to default view
374 */
375 void OpenGLWindow::defaultView()
376 {
377 _xModel = _yModel = _zModel = 0.0;
378 _scaleModel = 1.0;
379 _yRotationModel = 0.0;
380 }
381
382
383
384 /**
385 * Check if live mode is activated
386 * @return true, if activated
387 */
388 bool OpenGLWindow::liveActivated()
389 {
390 return _liveUpdates;
391 }