3025996b |
1 | // Copyright (C) 2006 Erik Dahlberg |
2 | // |
1a372e99 |
3 | // This file is part of LSystem3D. |
3025996b |
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), |
1b297ccb |
42 | FXMAPFUNC(SEL_PAINT, RenderingSurface::ID_CANVAS, RenderingSurface::onRepaint), |
43 | FXMAPFUNC(SEL_CLOSE, 0, RenderingSurface::onQuit) |
3025996b |
44 | }; |
45 | |
46 | // macro to set up class implementation |
47 | FXIMPLEMENT(RenderingSurface, FXMainWindow, RenderingSurfaceMap, ARRAYNUMBER(RenderingSurfaceMap)) |
48 | |
49 | |
50 | |
51 | /** |
52 | * Constructor |
1b297ccb |
53 | * @param application the application object |
3025996b |
54 | */ |
1b297ccb |
55 | RenderingSurface::RenderingSurface(FXApp *application) : FXMainWindow(application, "LSystem3D", NULL, NULL, DECOR_ALL, 100, 100, 800, 800) |
3025996b |
56 | { |
1b297ccb |
57 | _lsystem = NULL; |
3025996b |
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 | |
1b297ccb |
78 | /** |
79 | * Destructor |
80 | */ |
81 | RenderingSurface::~RenderingSurface() |
82 | { |
83 | delete _visual; |
84 | } |
85 | |
86 | |
87 | |
3025996b |
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(); |
1b297ccb |
98 | |
3025996b |
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 |
1b297ccb |
316 | _lsystem->render(); |
3025996b |
317 | |
318 | // make it appear |
319 | _canvas->swapBuffers(); |
320 | } |
1b297ccb |
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 | } |