Minor cleanup.
[lsystem3d.git] / src / renderingsurface.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 <GL/gl.h>
23 #include <GL/glu.h>
24
25 #include "fx.h"
26 #include "fx3d.h"
27
28 #include "renderingsurface.h"
29
30
31
32 // message map
33 FXDEFMAP(RenderingSurface) RenderingSurfaceMap[] =
34 {
35 FXMAPFUNC(SEL_LEFTBUTTONPRESS, RenderingSurface::ID_CANVAS, RenderingSurface::onLeftMouseDown),
36 FXMAPFUNC(SEL_LEFTBUTTONRELEASE, RenderingSurface::ID_CANVAS, RenderingSurface::onLeftMouseUp),
37 FXMAPFUNC(SEL_MIDDLEBUTTONPRESS, RenderingSurface::ID_CANVAS, RenderingSurface::onMiddleMouseDown),
38 FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE, RenderingSurface::ID_CANVAS, RenderingSurface::onMiddleMouseUp),
39 FXMAPFUNC(SEL_RIGHTBUTTONPRESS, RenderingSurface::ID_CANVAS, RenderingSurface::onRightMouseDown),
40 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, RenderingSurface::ID_CANVAS, RenderingSurface::onRightMouseUp),
41 FXMAPFUNC(SEL_MOTION, RenderingSurface::ID_CANVAS, RenderingSurface::onMouseMove),
42 FXMAPFUNC(SEL_PAINT, RenderingSurface::ID_CANVAS, RenderingSurface::onRepaint),
43 FXMAPFUNC(SEL_CLOSE, 0, RenderingSurface::onQuit)
44 };
45
46 // macro to set up class implementation
47 FXIMPLEMENT(RenderingSurface, FXMainWindow, RenderingSurfaceMap, ARRAYNUMBER(RenderingSurfaceMap))
48
49
50
51 /**
52 * Constructor
53 * @param application the application object
54 */
55 RenderingSurface::RenderingSurface(FXApp *application) : FXMainWindow(application, "LSystem3D", NULL, NULL, DECOR_ALL, 100, 100, 800, 800)
56 {
57 _lsystem = NULL;
58
59 _modelX = 0.0;
60 _modelY = 0.0;
61 _modelZ = -10.0;
62
63 _modelRotationY = 0.0;
64
65 _leftMouseDown = _rightMouseDown = _middleMouseDown = false;
66
67
68 // pixel format info
69 _visual = new FXGLVisual(getApp(), VISUAL_DOUBLEBUFFER);
70
71 // OpenGL drawing area
72 FXVerticalFrame *mainFrame = new FXVerticalFrame(this, LAYOUT_FILL_X | LAYOUT_FILL_Y);
73 _canvas = new FXGLCanvas(mainFrame, _visual, this, ID_CANVAS, LAYOUT_FILL_X | LAYOUT_FILL_Y);
74 }
75
76
77
78 /**
79 * Destructor
80 */
81 RenderingSurface::~RenderingSurface()
82 {
83 delete _visual;
84 }
85
86
87
88 /**
89 * Create and initialize the window
90 */
91 void RenderingSurface::create()
92 {
93 // create the window
94 FXMainWindow::create();
95
96 // set up OpenGL
97 _canvas->makeCurrent();
98
99 initOpenGL();
100
101 // make the window appear
102 show();
103 }
104
105
106
107 /**
108 * Initialize OpenGL
109 */
110 void RenderingSurface::initOpenGL()
111 {
112 // projection matrix
113 glMatrixMode(GL_PROJECTION);
114 glLoadIdentity();
115 gluPerspective(65, 1, 1, 500);
116
117 // modelview matrix
118 glMatrixMode(GL_MODELVIEW);
119 glLoadIdentity();
120
121
122 // global ambient light
123 GLfloat ambientLight[] = {0.7, 0.7, 0.7, 1.0};
124 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
125
126 // diffuse light
127 GLfloat lightPosition[] = {150.0, 150.0, 0.0, 0.0};
128 GLfloat whiteLight[] = {1.0, 1.0, 1.0, 1.0};
129 glLightfv(GL_LIGHT0, GL_DIFFUSE, whiteLight);
130 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
131
132
133 glEnable(GL_COLOR_MATERIAL);
134 glEnable(GL_LIGHTING);
135 glEnable(GL_LIGHT0);
136 glEnable(GL_DEPTH_TEST);
137 }
138
139
140
141 /**
142 * Force an update of the rendering surface
143 */
144 void RenderingSurface::draw()
145 {
146 _canvas->update();
147 }
148
149
150
151 /**
152 * Called by the system when the left mouse button is pressed
153 * @param sender the sender object
154 * @param selector message type and id
155 * @param data event related data
156 * @return
157 */
158 long RenderingSurface::onLeftMouseDown(FXObject *sender, FXSelector selector, void *data)
159 {
160 _leftMouseDown = true;
161 }
162
163
164
165 /**
166 * Called by the system when the left mouse button is released
167 * @param sender the sender object
168 * @param selector message type and id
169 * @param data event related data
170 * @return
171 */
172 long RenderingSurface::onLeftMouseUp(FXObject *sender, FXSelector selector, void *data)
173 {
174 _leftMouseDown = false;
175 }
176
177
178
179 /**
180 * Called by the system when the middle mouse button is pressed
181 * @param sender the sender object
182 * @param selector message type and id
183 * @param data event related data
184 * @return
185 */
186 long RenderingSurface::onMiddleMouseDown(FXObject *sender, FXSelector selector, void *data)
187 {
188 _middleMouseDown = true;
189 }
190
191
192
193 /**
194 * Called by the system when the middle mouse button is released
195 * @param sender the sender object
196 * @param selector message type and id
197 * @param data event related data
198 * @return
199 */
200 long RenderingSurface::onMiddleMouseUp(FXObject *sender, FXSelector selector, void *data)
201 {
202 _middleMouseDown = false;
203 }
204
205
206
207 /**
208 * Called by the system when the right mouse button is pressed
209 * @param sender the sender object
210 * @param selector message type and id
211 * @param data event related data
212 * @return
213 */
214 long RenderingSurface::onRightMouseDown(FXObject *sender, FXSelector selector, void *data)
215 {
216 _rightMouseDown = true;
217 }
218
219
220
221 /**
222 * Called by the system when the right mouse button is released
223 * @param sender the sender object
224 * @param selector message type and id
225 * @param data event related data
226 * @return
227 */
228 long RenderingSurface::onRightMouseUp(FXObject *sender, FXSelector selector, void *data)
229 {
230 _rightMouseDown = false;
231 }
232
233
234
235 /**
236 * Called by the system when the mouse is moved
237 * @param sender the sender object
238 * @param selector message type and id
239 * @param data event related data
240 * @return
241 */
242 long RenderingSurface::onMouseMove(FXObject *sender, FXSelector selector, void *data)
243 {
244 // check status of the mouse buttons and move model
245
246 // left mouse button
247 if (_leftMouseDown)
248 {
249 // move in z-plane
250
251 FXEvent *event = (FXEvent*)data;
252
253 // TODO: "gluPerspective(65, 1, 1, 500)" -> "translateFactor = 610.0 / (-_modelZ)", ugly...
254 double translateFactor = 610.0 / (-_modelZ);
255
256 _modelX += (event->win_x - event->last_x) / translateFactor;
257 _modelY += -(event->win_y - event->last_y) / translateFactor;
258
259 _canvas->update();
260 }
261
262 // middle mouse button
263 if (_middleMouseDown)
264 {
265 // zoom in/out
266
267 FXEvent *event = (FXEvent*)data;
268
269 _modelZ += -(event->win_y - event->last_y) / 10.0;
270
271 // stop zooming at -1.0
272 if (_modelZ >= -1.0)
273 {
274 _modelZ = -1.0;
275 }
276
277 _canvas->update();
278 }
279
280 // right mouse button
281 if (_rightMouseDown)
282 {
283 // rotate around y-axis
284
285 FXEvent *event = (FXEvent*)data;
286
287 _modelRotationY = ((int)_modelRotationY + event->win_x - event->last_x) % 360;
288
289 _canvas->update();
290 }
291 }
292
293
294
295 /**
296 * Called by the system when the rendering surface needs a repaint
297 * @param sender the sender object
298 * @param selector message type and id
299 * @param data event related data
300 * @return
301 */
302 long RenderingSurface::onRepaint(FXObject *sender, FXSelector selector, void *data)
303 {
304 glMatrixMode (GL_MODELVIEW);
305 glLoadIdentity();
306
307
308 // clear scene
309 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
310
311 // position and orientation of model
312 glTranslatef(_modelX, _modelY, _modelZ);
313 glRotatef(_modelRotationY, 0.0, 1.0, 0.0);
314
315 // render model
316 _lsystem->render();
317
318 // make it appear
319 _canvas->swapBuffers();
320 }
321
322
323
324 /**
325 * Called by the system when the close button is pressed
326 * @param sender the sender object
327 * @param selector message type and id
328 * @param data event related data
329 * @return
330 */
331 long RenderingSurface::onQuit(FXObject *sender, FXSelector selector, void *data)
332 {
333 getApp()->exit(0);
334
335 return 1;
336 }
337
338
339
340 /**
341 * Set current L-system generator
342 * @param lsystem the L-system generator
343 */
344 void RenderingSurface::setLSystem(LindenmayerSystem *lsystem)
345 {
346 _lsystem = lsystem;
347 }