15c82487 |
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 | } |