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), |
42 | FXMAPFUNC(SEL_PAINT, RenderingSurface::ID_CANVAS, RenderingSurface::onRepaint) |
43 | }; |
44 | |
45 | // macro to set up class implementation |
46 | FXIMPLEMENT(RenderingSurface, FXMainWindow, RenderingSurfaceMap, ARRAYNUMBER(RenderingSurfaceMap)) |
47 | |
48 | |
49 | |
50 | /** |
51 | * Constructor |
52 | * @param application the FOX application object |
53 | * @param lsystem the Lindenmayer-system |
54 | */ |
55 | RenderingSurface::RenderingSurface(FXApp *application, LindenmayerSystem *lsystem) : FXMainWindow(application, "LSystem3D", NULL, NULL, DECOR_ALL, 100, 100, 800, 800) |
56 | { |
57 | _lsystem = lsystem; |
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 | * Create and initialize the window |
80 | */ |
81 | void RenderingSurface::create() |
82 | { |
83 | // create the window |
84 | FXMainWindow::create(); |
85 | |
86 | // set up OpenGL |
87 | _canvas->makeCurrent(); |
88 | initOpenGL(); |
89 | |
90 | // make the window appear |
91 | show(); |
92 | } |
93 | |
94 | |
95 | |
96 | /** |
97 | * Initialize OpenGL |
98 | */ |
99 | void RenderingSurface::initOpenGL() |
100 | { |
101 | // projection matrix |
102 | glMatrixMode(GL_PROJECTION); |
103 | glLoadIdentity(); |
104 | gluPerspective(65, 1, 1, 500); |
105 | |
106 | // modelview matrix |
107 | glMatrixMode(GL_MODELVIEW); |
108 | glLoadIdentity(); |
109 | |
110 | |
111 | // global ambient light |
112 | GLfloat ambientLight[] = {0.7, 0.7, 0.7, 1.0}; |
113 | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight); |
114 | |
115 | // diffuse light |
116 | GLfloat lightPosition[] = {150.0, 150.0, 0.0, 0.0}; |
117 | GLfloat whiteLight[] = {1.0, 1.0, 1.0, 1.0}; |
118 | glLightfv(GL_LIGHT0, GL_DIFFUSE, whiteLight); |
119 | glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); |
120 | |
121 | |
122 | glEnable(GL_COLOR_MATERIAL); |
123 | glEnable(GL_LIGHTING); |
124 | glEnable(GL_LIGHT0); |
125 | glEnable(GL_DEPTH_TEST); |
126 | } |
127 | |
128 | |
129 | |
130 | /** |
131 | * Force an update of the rendering surface |
132 | */ |
133 | void RenderingSurface::draw() |
134 | { |
135 | _canvas->update(); |
136 | } |
137 | |
138 | |
139 | |
140 | /** |
141 | * Called by the system when the left mouse button is pressed |
142 | * @param sender the sender object |
143 | * @param selector message type and id |
144 | * @param data event related data |
145 | * @return |
146 | */ |
147 | long RenderingSurface::onLeftMouseDown(FXObject *sender, FXSelector selector, void *data) |
148 | { |
149 | _leftMouseDown = true; |
150 | } |
151 | |
152 | |
153 | |
154 | /** |
155 | * Called by the system when the left mouse button is released |
156 | * @param sender the sender object |
157 | * @param selector message type and id |
158 | * @param data event related data |
159 | * @return |
160 | */ |
161 | long RenderingSurface::onLeftMouseUp(FXObject *sender, FXSelector selector, void *data) |
162 | { |
163 | _leftMouseDown = false; |
164 | } |
165 | |
166 | |
167 | |
168 | /** |
169 | * Called by the system when the middle mouse button is pressed |
170 | * @param sender the sender object |
171 | * @param selector message type and id |
172 | * @param data event related data |
173 | * @return |
174 | */ |
175 | long RenderingSurface::onMiddleMouseDown(FXObject *sender, FXSelector selector, void *data) |
176 | { |
177 | _middleMouseDown = true; |
178 | } |
179 | |
180 | |
181 | |
182 | /** |
183 | * Called by the system when the middle mouse button is released |
184 | * @param sender the sender object |
185 | * @param selector message type and id |
186 | * @param data event related data |
187 | * @return |
188 | */ |
189 | long RenderingSurface::onMiddleMouseUp(FXObject *sender, FXSelector selector, void *data) |
190 | { |
191 | _middleMouseDown = false; |
192 | } |
193 | |
194 | |
195 | |
196 | /** |
197 | * Called by the system when the right mouse button is pressed |
198 | * @param sender the sender object |
199 | * @param selector message type and id |
200 | * @param data event related data |
201 | * @return |
202 | */ |
203 | long RenderingSurface::onRightMouseDown(FXObject *sender, FXSelector selector, void *data) |
204 | { |
205 | _rightMouseDown = true; |
206 | } |
207 | |
208 | |
209 | |
210 | /** |
211 | * Called by the system when the right mouse button is released |
212 | * @param sender the sender object |
213 | * @param selector message type and id |
214 | * @param data event related data |
215 | * @return |
216 | */ |
217 | long RenderingSurface::onRightMouseUp(FXObject *sender, FXSelector selector, void *data) |
218 | { |
219 | _rightMouseDown = false; |
220 | } |
221 | |
222 | |
223 | |
224 | /** |
225 | * Called by the system when the mouse is moved |
226 | * @param sender the sender object |
227 | * @param selector message type and id |
228 | * @param data event related data |
229 | * @return |
230 | */ |
231 | long RenderingSurface::onMouseMove(FXObject *sender, FXSelector selector, void *data) |
232 | { |
233 | // check status of the mouse buttons and move model |
234 | |
235 | // left mouse button |
236 | if (_leftMouseDown) |
237 | { |
238 | // move in z-plane |
239 | |
240 | FXEvent *event = (FXEvent*)data; |
241 | |
242 | // TODO: "gluPerspective(65, 1, 1, 500)" -> "translateFactor = 610.0 / (-_modelZ)", ugly... |
243 | double translateFactor = 610.0 / (-_modelZ); |
244 | |
245 | _modelX += (event->win_x - event->last_x) / translateFactor; |
246 | _modelY += -(event->win_y - event->last_y) / translateFactor; |
247 | |
248 | _canvas->update(); |
249 | } |
250 | |
251 | // middle mouse button |
252 | if (_middleMouseDown) |
253 | { |
254 | // zoom in/out |
255 | |
256 | FXEvent *event = (FXEvent*)data; |
257 | |
258 | _modelZ += -(event->win_y - event->last_y) / 10.0; |
259 | |
260 | // stop zooming at -1.0 |
261 | if (_modelZ >= -1.0) |
262 | { |
263 | _modelZ = -1.0; |
264 | } |
265 | |
266 | _canvas->update(); |
267 | } |
268 | |
269 | // right mouse button |
270 | if (_rightMouseDown) |
271 | { |
272 | // rotate around y-axis |
273 | |
274 | FXEvent *event = (FXEvent*)data; |
275 | |
276 | _modelRotationY = ((int)_modelRotationY + event->win_x - event->last_x) % 360; |
277 | |
278 | _canvas->update(); |
279 | } |
280 | } |
281 | |
282 | |
283 | |
284 | /** |
285 | * Called by the system when the rendering surface needs a repaint |
286 | * @param sender the sender object |
287 | * @param selector message type and id |
288 | * @param data event related data |
289 | * @return |
290 | */ |
291 | long RenderingSurface::onRepaint(FXObject *sender, FXSelector selector, void *data) |
292 | { |
293 | glMatrixMode (GL_MODELVIEW); |
294 | glLoadIdentity(); |
295 | |
296 | |
297 | // clear scene |
298 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
299 | |
300 | // position and orientation of model |
301 | glTranslatef(_modelX, _modelY, _modelZ); |
302 | glRotatef(_modelRotationY, 0.0, 1.0, 0.0); |
303 | |
304 | // render model |
305 | _lsystem->getModel()->draw(); |
306 | |
307 | |
308 | // make it appear |
309 | _canvas->swapBuffers(); |
310 | } |