1 /********************************************************************************
2 * *
3 * O p e n G L V i e w e r *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1997,2006 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
21 *********************************************************************************
22 * $Id: FXGLViewer.cpp,v 1.156.2.1 2006/08/02 01:31:08 fox Exp $ *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxkeys.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXVec2f.h"
32 #include "FXVec3f.h"
33 #include "FXVec4f.h"
34 #include "FXQuatf.h"
35 #include "FXMat4f.h"
36 #include "FXRangef.h"
37 #include "FXString.h"
38 #include "FXSize.h"
39 #include "FXPoint.h"
40 #include "FXRectangle.h"
41 #include "FXSettings.h"
42 #include "FXRegistry.h"
43 #include "FXAccelTable.h"
44 #include "FXObjectList.h"
45 #include "FXApp.h"
46 #include "FXVisual.h"
47 #include "FXGLVisual.h"
48 #include "FXDC.h"
49 #include "FXDCWindow.h"
50 #include "FXDCPrint.h"
51 #include "FXMessageBox.h"
52 #include "FXToolTip.h"
53 #include "FXCursor.h"
54 #include "FXGLContext.h"
55 #include "FXGLViewer.h"
56 #include "FXGLObject.h"
57 #include "FXPrintDialog.h"
58 #include "jitter.h"
59
60 /*
61 To Do:
62 - Initialize GL to fastest of everything for drawing lines.
63 - Group object needs current element.
64 - use app->getDragDelta() for motion tolerance.
65 - Default op to noop mode; all returns 0 in noop mode.
66 - GLuint unfortunately not always big enough to store a pointer...
67 - The selection seems to get lost with multiple viewers into.
68 the same scene. If you select a cube in one view, then select another
69 cube in another view, both seem to get selected. Can we push the
70 "selection" member from the view to the scene object?
71 - Instead of select/deselect, do focus gain/lost type deal.
72 - Add methods for inquire of pick-ray.
73 - Fix FXGLGroup to identify child or itself..
74 - Need some way of updating ALL viewers.
75 - Need a document/view type concept?
76 - Load/Save need to save more...
77 - Build mini display lists for offset/surface drawing.
78 - Pass clicked/double-clicked/triple-clicked messages to object.
79 - Distinguish between current object and selected ones.
80 only one is current, but many may be selected.
81 - When object(s) deleted, need to fix up selection...
82 - GLViewer should source some messages to its target for important events.
83 - Zoom-lasso feature.
84 - Basic mouse actions:
85
86 State Event Modifiers Where State Meaning
87 --------------------------------------------------------------------------------------------
88 HOVERING Left -- outside PICKING Pick an object if no move
89 PICKING Motion -- -- ROTATING Rotate camera about target point
90 HOVERING Left -- inside object DRAGGING Drag object
91 HOVERING Left Shift -- LASSOSELECT Select
92 HOVERING Left Control -- LASSOSELECT Toggle selection
93 HOVERING Left Right -- ZOOMING Zoom in
94 HOVERING Left Right + Shift -- TRUCKING Trucking camera
95 HOVERING Middle -- -- ZOOMING Zoom in/out
96 HOVERING Middle Shift -- TRUCKING Trucking camera
97 HOVERING Right -- -- POSTING Post popup menu if no move
98 POSTING Motion -- -- TRANSLATING Translate camera
99 HOVERING Right Shift -- GYRATING Rotate object about camera
100 HOVERING Right Control -- FOVING Change field of view
101 HOVERING Right Left -- ZOOMING Zoom in
102 HOVERING Right Left +Shift -- TRUCKING Trucking camera
103
104 FIXME FIXME FIXME FIXME FIXME FIXME FIXME
105
106 Should remove "selection" member. FXGLViewer should have no knowledge
107 of any GL object besides scene.
108
109 Should delegate all messages it does not understand to "target" and not
110 to current object.
111
112 Picking, selection should pass list of records in callback; this list
113 should NOT contain zmin, zmax, but just, for each record: number of
114 names, and the names. List is ended by 0 (no names) record.
115
116 The list should be sorted based on zmin, zmax, with first record in list
117 being the one closest to the eye.
118
119 Should add FXGLLight objects, which can be added to FXGLGroups.
120
121 Should add subclass of FXGLGroup which pushes/pops attributes.
122
123 Note that we will keep the camera state in the FXGLViewer widget, i.e.
124 won't have camera objects.
125
126 FIXME FIXME FIXME FIXME FIXME FIXME FIXME
127
128 - Need 3 dials to rotate about model (not screen) axes.
129
130 - Zoom centered on point at which you started the zoom operation.
131 */
132
133
134 // Size of pick buffer
135 #define MAX_PICKBUF 1024
136
137 // Maximum length of selection path
138 #define MAX_SELPATH 64
139
140 // Rotation tolerance
141 #define EPS 1.0E-2
142
143 // Pick tolerance
144 #define PICK_TOL 3
145
146 using namespace FX;
147
148 /*******************************************************************************/
149
150 namespace FX {
151
152 // Map
153 FXDEFMAP(FXGLViewer) FXGLViewerMap[]={
154 FXMAPFUNC(SEL_PAINT,0,FXGLViewer::onPaint),
155 FXMAPFUNC(SEL_MOTION,0,FXGLViewer::onMotion),
156 FXMAPFUNC(SEL_MOUSEWHEEL,0,FXGLViewer::onMouseWheel),
157 FXMAPFUNC(SEL_TIMEOUT,FXGLViewer::ID_TIPTIMER,FXGLViewer::onTipTimer),
158 FXMAPFUNC(SEL_DND_ENTER,0,FXGLViewer::onDNDEnter),
159 FXMAPFUNC(SEL_DND_LEAVE,0,FXGLViewer::onDNDLeave),
160 FXMAPFUNC(SEL_DND_DROP,0,FXGLViewer::onDNDDrop),
161 FXMAPFUNC(SEL_DND_MOTION,0,FXGLViewer::onDNDMotion),
162 FXMAPFUNC(SEL_ENTER,0,FXGLViewer::onEnter),
163 FXMAPFUNC(SEL_LEAVE,0,FXGLViewer::onLeave),
164 FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXGLViewer::onLeftBtnPress),
165 FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXGLViewer::onLeftBtnRelease),
166 FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,FXGLViewer::onMiddleBtnPress),
167 FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE,0,FXGLViewer::onMiddleBtnRelease),
168 FXMAPFUNC(SEL_RIGHTBUTTONPRESS,0,FXGLViewer::onRightBtnPress),
169 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,0,FXGLViewer::onRightBtnRelease),
170 FXMAPFUNC(SEL_UNGRABBED,0,FXGLViewer::onUngrabbed),
171 FXMAPFUNC(SEL_KEYPRESS,0,FXGLViewer::onKeyPress),
172 FXMAPFUNC(SEL_KEYRELEASE,0,FXGLViewer::onKeyRelease),
173 FXMAPFUNC(SEL_FOCUSIN,0,FXGLViewer::onFocusIn),
174 FXMAPFUNC(SEL_FOCUSOUT,0,FXGLViewer::onFocusOut),
175 FXMAPFUNC(SEL_CHANGED,0,FXGLViewer::onChanged),
176 FXMAPFUNC(SEL_CLICKED,0,FXGLViewer::onClicked),
177 FXMAPFUNC(SEL_DOUBLECLICKED,0,FXGLViewer::onDoubleClicked),
178 FXMAPFUNC(SEL_TRIPLECLICKED,0,FXGLViewer::onTripleClicked),
179 FXMAPFUNC(SEL_LASSOED,0,FXGLViewer::onLassoed),
180 FXMAPFUNC(SEL_SELECTED,0,FXGLViewer::onSelected),
181 FXMAPFUNC(SEL_DESELECTED,0,FXGLViewer::onDeselected),
182 FXMAPFUNC(SEL_INSERTED,0,FXGLViewer::onInserted),
183 FXMAPFUNC(SEL_DELETED,0,FXGLViewer::onDeleted),
184 FXMAPFUNC(SEL_PICKED,0,FXGLViewer::onPick),
185 FXMAPFUNC(SEL_CLIPBOARD_LOST,0,FXGLViewer::onClipboardLost),
186 FXMAPFUNC(SEL_CLIPBOARD_GAINED,0,FXGLViewer::onClipboardGained),
187 FXMAPFUNC(SEL_CLIPBOARD_REQUEST,0,FXGLViewer::onClipboardRequest),
188 FXMAPFUNC(SEL_QUERY_TIP,0,FXGLViewer::onQueryTip),
189 FXMAPFUNC(SEL_QUERY_HELP,0,FXGLViewer::onQueryHelp),
190 FXMAPFUNCS(SEL_UPDATE,FXGLViewer::ID_DIAL_X,FXGLViewer::ID_DIAL_Z,FXGLViewer::onUpdXYZDial),
191 FXMAPFUNCS(SEL_CHANGED,FXGLViewer::ID_DIAL_X,FXGLViewer::ID_DIAL_Z,FXGLViewer::onCmdXYZDial),
192 FXMAPFUNCS(SEL_COMMAND,FXGLViewer::ID_DIAL_X,FXGLViewer::ID_DIAL_Z,FXGLViewer::onCmdXYZDial),
193 FXMAPFUNCS(SEL_UPDATE,FXGLViewer::ID_ROLL,FXGLViewer::ID_YAW,FXGLViewer::onUpdRollPitchYaw),
194 FXMAPFUNCS(SEL_COMMAND,FXGLViewer::ID_ROLL,FXGLViewer::ID_YAW,FXGLViewer::onCmdRollPitchYaw),
195 FXMAPFUNCS(SEL_CHANGED,FXGLViewer::ID_ROLL,FXGLViewer::ID_YAW,FXGLViewer::onCmdRollPitchYaw),
196 FXMAPFUNCS(SEL_UPDATE,FXGLViewer::ID_SCALE_X,FXGLViewer::ID_SCALE_Z,FXGLViewer::onUpdXYZScale),
197 FXMAPFUNCS(SEL_COMMAND,FXGLViewer::ID_SCALE_X,FXGLViewer::ID_SCALE_Z,FXGLViewer::onCmdXYZScale),
198 FXMAPFUNCS(SEL_CHANGED,FXGLViewer::ID_SCALE_X,FXGLViewer::ID_SCALE_Z,FXGLViewer::onCmdXYZScale),
199 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_PERSPECTIVE,FXGLViewer::onUpdPerspective),
200 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_PERSPECTIVE,FXGLViewer::onCmdPerspective),
201 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_PARALLEL,FXGLViewer::onUpdParallel),
202 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_PARALLEL,FXGLViewer::onCmdParallel),
203 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_FRONT,FXGLViewer::onUpdFront),
204 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_FRONT,FXGLViewer::onCmdFront),
205 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_BACK,FXGLViewer::onUpdBack),
206 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_BACK,FXGLViewer::onCmdBack),
207 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_LEFT,FXGLViewer::onUpdLeft),
208 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_LEFT,FXGLViewer::onCmdLeft),
209 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_RIGHT,FXGLViewer::onUpdRight),
210 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_RIGHT,FXGLViewer::onCmdRight),
211 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_TOP,FXGLViewer::onUpdTop),
212 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_TOP,FXGLViewer::onCmdTop),
213 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_BOTTOM,FXGLViewer::onUpdBottom),
214 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_BOTTOM,FXGLViewer::onCmdBottom),
215 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_RESETVIEW,FXWindow::onUpdYes),
216 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_RESETVIEW,FXGLViewer::onCmdResetView),
217 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_FITVIEW,FXWindow::onUpdYes),
218 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_FITVIEW,FXGLViewer::onCmdFitView),
219 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_CUT_SEL,FXGLViewer::onUpdDeleteSel),
220 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_CUT_SEL,FXGLViewer::onCmdCutSel),
221 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_COPY_SEL,FXGLViewer::onUpdCurrent),
222 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_COPY_SEL,FXGLViewer::onCmdCopySel),
223 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_PASTE_SEL,FXGLViewer::onUpdYes),
224 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_PASTE_SEL,FXGLViewer::onCmdPasteSel),
225 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_DELETE_SEL,FXGLViewer::onUpdDeleteSel),
226 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_DELETE_SEL,FXGLViewer::onCmdDeleteSel),
227 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_BACK_COLOR,FXGLViewer::onUpdBackColor),
228 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_BACK_COLOR,FXGLViewer::onCmdBackColor),
229 FXMAPFUNC(SEL_CHANGED,FXGLViewer::ID_BACK_COLOR,FXGLViewer::onCmdBackColor),
230 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_AMBIENT_COLOR,FXGLViewer::onUpdAmbientColor),
231 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_AMBIENT_COLOR,FXGLViewer::onCmdAmbientColor),
232 FXMAPFUNC(SEL_CHANGED,FXGLViewer::ID_AMBIENT_COLOR,FXGLViewer::onCmdAmbientColor),
233 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_LIGHTING,FXGLViewer::onUpdLighting),
234 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_LIGHTING,FXGLViewer::onCmdLighting),
235 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_FOG,FXGLViewer::onUpdFog),
236 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_DITHER,FXGLViewer::onUpdDither),
237 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_LIGHT_AMBIENT,FXGLViewer::onUpdLightAmbient),
238 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_LIGHT_AMBIENT,FXGLViewer::onCmdLightAmbient),
239 FXMAPFUNC(SEL_CHANGED,FXGLViewer::ID_LIGHT_AMBIENT,FXGLViewer::onCmdLightAmbient),
240 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_LIGHT_DIFFUSE,FXGLViewer::onUpdLightDiffuse),
241 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_LIGHT_DIFFUSE,FXGLViewer::onCmdLightDiffuse),
242 FXMAPFUNC(SEL_CHANGED,FXGLViewer::ID_LIGHT_DIFFUSE,FXGLViewer::onCmdLightDiffuse),
243 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_LIGHT_SPECULAR,FXGLViewer::onUpdLightSpecular),
244 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_LIGHT_SPECULAR,FXGLViewer::onCmdLightSpecular),
245 FXMAPFUNC(SEL_CHANGED,FXGLViewer::ID_LIGHT_SPECULAR,FXGLViewer::onCmdLightSpecular),
246 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_TURBO,FXGLViewer::onUpdTurbo),
247 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_TURBO,FXGLViewer::onCmdTurbo),
248 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_PRINT_IMAGE,FXGLViewer::onUpdYes),
249 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_PRINT_VECTOR,FXGLViewer::onUpdYes),
250 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_LASSO_ZOOM,FXGLViewer::onUpdYes),
251 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_LASSO_ZOOM,FXGLViewer::onCmdLassoZoom),
252 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_LASSO_SELECT,FXGLViewer::onUpdYes),
253 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_LASSO_SELECT,FXGLViewer::onCmdLassoSelect),
254 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_FOG,FXGLViewer::onCmdFog),
255 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_DITHER,FXGLViewer::onCmdDither),
256 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_FOV,FXGLViewer::onUpdFov),
257 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_FOV,FXGLViewer::onCmdFov),
258 FXMAPFUNC(SEL_CHANGED,FXGLViewer::ID_FOV,FXGLViewer::onCmdFov),
259 FXMAPFUNC(SEL_UPDATE,FXGLViewer::ID_ZOOM,FXGLViewer::onUpdZoom),
260 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_ZOOM,FXGLViewer::onCmdZoom),
261 FXMAPFUNC(SEL_CHANGED,FXGLViewer::ID_ZOOM,FXGLViewer::onCmdZoom),
262 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_PRINT_IMAGE,FXGLViewer::onCmdPrintImage),
263 FXMAPFUNC(SEL_COMMAND,FXGLViewer::ID_PRINT_VECTOR,FXGLViewer::onCmdPrintVector),
264 FXMAPFUNCS(SEL_UPDATE,FXGLViewer::ID_TOP_COLOR,FXGLViewer::ID_BOTTOM_COLOR,FXGLViewer::onUpdGradientBackColor),
265 FXMAPFUNCS(SEL_COMMAND,FXGLViewer::ID_TOP_COLOR,FXGLViewer::ID_BOTTOM_COLOR,FXGLViewer::onCmdGradientBackColor),
266 FXMAPFUNCS(SEL_CHANGED,FXGLViewer::ID_TOP_COLOR,FXGLViewer::ID_BOTTOM_COLOR,FXGLViewer::onCmdGradientBackColor),
267 };
268
269
270 // Object implementation
271 FXIMPLEMENT(FXGLViewer,FXGLCanvas,FXGLViewerMap,ARRAYNUMBER(FXGLViewerMap))
272
273
274 /*******************************************************************************/
275
276 // Drag type names for generic object
277 const FXchar FXGLViewer::objectTypeName[]="application/x-globject";
278
279
280 // Drag type for generic object
281 FXDragType FXGLViewer::objectType=0;
282
283
284 /*******************************************************************************/
285
286
287 // For deserialization
FXGLViewer()288 FXGLViewer::FXGLViewer(){
289 flags|=FLAG_ENABLED|FLAG_DROPTARGET;
290 dial[0]=0;
291 dial[1]=0;
292 dial[2]=0;
293 dropped=NULL;
294 selection=NULL;
295 zsortfunc=NULL;
296 doesturbo=FALSE;
297 mode=HOVERING;
298 }
299
300
301 // Construct GL viewer widget with private display list
FXGLViewer(FXComposite * p,FXGLVisual * vis,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h)302 FXGLViewer::FXGLViewer(FXComposite* p,FXGLVisual *vis,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h):
303 FXGLCanvas(p,vis,NULL,tgt,sel,opts,x,y,w,h){
304 initialize();
305 }
306
307
308 // Construct GL viewer widget with shared display list
FXGLViewer(FXComposite * p,FXGLVisual * vis,FXGLViewer * sharegroup,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h)309 FXGLViewer::FXGLViewer(FXComposite* p,FXGLVisual *vis,FXGLViewer* sharegroup,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h):
310 FXGLCanvas(p,vis,sharegroup,tgt,sel,opts,x,y,w,h){
311 initialize();
312 }
313
314
315 // Common initialization for constructor
initialize()316 void FXGLViewer::initialize(){
317 flags|=FLAG_ENABLED|FLAG_DROPTARGET;
318 defaultCursor=getApp()->getDefaultCursor(DEF_CROSSHAIR_CURSOR);
319 dragCursor=getApp()->getDefaultCursor(DEF_CROSSHAIR_CURSOR);
320 projection=PERSPECTIVE; // Projection
321 zoom=1.0; // Zoom factor
322 fov=30.0; // Field of view (1 to 90)
323 wvt.left=-1.0; // Init world box
324 wvt.right=1.0;
325 wvt.top=1.0;
326 wvt.bottom=-1.0;
327 wvt.hither=0.1;
328 wvt.yon=1.0;
329 wvt.w=100; // Viewport width
330 wvt.h=100; // Viewport height
331 diameter=2.0; // Size of model
332 distance=7.464116; // Distance of PRP to target
333 rotation.x=0.0f; // Orientation
334 rotation.y=0.0f;
335 rotation.z=0.0f;
336 rotation.w=1.0f;
337 center.x=0.0f; // Model center
338 center.y=0.0f;
339 center.z=0.0f;
340 scale.x=1.0f; // Model scaling
341 scale.y=1.0f;
342 scale.z=1.0f;
343 updateProjection(); // Initial projection
344 updateTransform(); // Set transformation
345 maxhits=512; // Maximum hit buffer size
346 background[0][0]=0.5f; // Top background
347 background[0][1]=0.5f;
348 background[0][2]=1.0f;
349 background[0][3]=1.0f;
350 background[1][0]=1.0f; // Bottom background
351 background[1][1]=1.0f;
352 background[1][2]=1.0f;
353 background[1][3]=1.0f;
354 ambient[0]=0.2f; // Scene ambient
355 ambient[1]=0.2f;
356 ambient[2]=0.2f;
357 ambient[3]=1.0f;
358 light.ambient[0]=0.0f; // Light ambient
359 light.ambient[1]=0.0f;
360 light.ambient[2]=0.0f;
361 light.ambient[3]=1.0f;
362 light.diffuse[0]=1.0f; // Light diffuse
363 light.diffuse[1]=1.0f;
364 light.diffuse[2]=1.0f;
365 light.diffuse[3]=1.0f;
366 light.specular[0]=0.0f; // Light specular
367 light.specular[1]=0.0f;
368 light.specular[2]=0.0f;
369 light.specular[3]=1.0f;
370 light.position[0]=-2.0f; // Light position
371 light.position[1]= 2.0f;
372 light.position[2]= 5.0f;
373 light.position[3]= 0.0f;
374 light.direction[0]= 0.0f; // Light direction
375 light.direction[1]= 0.0f;
376 light.direction[2]=-1.0f;
377 light.exponent=0.0f; // Light spot exponent
378 light.cutoff=180.0f; // Light spot cutoff
379 light.c_attn=1.0f; // Light constant attenuation
380 light.l_attn=0.0f; // Light linear attenuation
381 light.q_attn=0.0f; // Light quadratic attenuation
382 material.ambient[0]=0.2f; // Material ambient reflectivity
383 material.ambient[1]=0.2f;
384 material.ambient[2]=0.2f;
385 material.ambient[3]=1.0f;
386 material.diffuse[0]=0.8f; // Material diffuse reflectivity
387 material.diffuse[1]=0.8f;
388 material.diffuse[2]=0.8f;
389 material.diffuse[3]=1.0f;
390 material.specular[0]=1.0f; // Material specular reflectivity
391 material.specular[1]=1.0f;
392 material.specular[2]=1.0f;
393 material.specular[3]=1.0f;
394 material.emission[0]=0.0f; // Material emissivity
395 material.emission[1]=0.0f;
396 material.emission[2]=0.0f;
397 material.emission[3]=1.0f;
398 material.shininess=30.0f; // Material shininess
399 dial[0]=0; // Old dial position
400 dial[1]=0; // Old dial position
401 dial[2]=0; // Old dial position
402 dropped=NULL; // Nobody being dropped on
403 selection=NULL; // No initial selection
404 zsortfunc=NULL; // Routine to sort feedback buffer
405 scene=NULL; // Scene to look at
406 doesturbo=FALSE; // In interaction
407 turbomode=FALSE; // Turbo mode
408 mode=HOVERING; // Mouse operation
409 }
410
411
412 // Create window
create()413 void FXGLViewer::create(){
414 FXRangef r(-1.0f,1.0f,-1.0f,1.0f,-1.0f,1.0f);
415
416 // We would like to have this be true
417 #ifdef HAVE_GL_H
418 FXASSERT(sizeof(FXuint)==sizeof(GLuint));
419 #endif
420
421 // Create Window
422 FXGLCanvas::create();
423
424 // Set up OpenGL environment
425 glsetup();
426
427 // Register drag type for color
428 if(!colorType){colorType=getApp()->registerDragType(colorTypeName);}
429 if(!objectType){objectType=getApp()->registerDragType(objectTypeName);}
430
431 // If have scene already, get correct bounds
432 if(scene) scene->bounds(r);
433
434 // Set initial viewing volume
435 setBounds(r);
436 }
437
438
439 // Detach window
detach()440 void FXGLViewer::detach(){
441 FXGLCanvas::detach();
442 colorType=0;
443 objectType=0;
444 }
445
446
447 /********************* V i e w i n g S e t u p ***************************/
448
449
450 // Set up GL context
glsetup()451 void FXGLViewer::glsetup(){
452 #ifdef HAVE_GL_H
453
454 // Make GL context current
455 if(makeCurrent()){
456
457 // Initialize GL context
458 glRenderMode(GL_RENDER);
459
460 // Fast hints
461 glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST);
462 glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_FASTEST);
463 glHint(GL_FOG_HINT,GL_FASTEST);
464 glHint(GL_LINE_SMOOTH_HINT,GL_FASTEST);
465 glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
466
467 // Z-buffer test on
468 glEnable(GL_DEPTH_TEST);
469 glDepthFunc(GL_LESS);
470 glDepthRange(0.0,1.0);
471 glClearDepth(1.0);
472 glClearColor(background[0][0],background[0][1],background[0][2],background[0][3]);
473
474 // No face culling
475 glDisable(GL_CULL_FACE);
476 glCullFace(GL_BACK);
477 glFrontFace(GL_CCW);
478
479 // Two sided lighting
480 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,TRUE);
481 glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient);
482
483 // Preferred blend over background
484 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
485
486 // Light on
487 glEnable(GL_LIGHT0);
488 glLightfv(GL_LIGHT0,GL_AMBIENT,light.ambient);
489 glLightfv(GL_LIGHT0,GL_DIFFUSE,light.diffuse);
490 glLightfv(GL_LIGHT0,GL_SPECULAR,light.specular);
491 glLightfv(GL_LIGHT0,GL_POSITION,light.position);
492 glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,light.direction);
493 glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,light.exponent);
494 glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,light.cutoff);
495 glLightf(GL_LIGHT0,GL_CONSTANT_ATTENUATION,light.c_attn);
496 glLightf(GL_LIGHT0,GL_LINEAR_ATTENUATION,light.l_attn);
497 glLightf(GL_LIGHT0,GL_QUADRATIC_ATTENUATION,light.q_attn);
498
499 // Viewer is close
500 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,TRUE);
501
502 // Material colors
503 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,material.ambient);
504 glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,material.diffuse);
505 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,material.specular);
506 glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,material.emission);
507 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,material.shininess);
508
509 // Vertex colors change both diffuse and ambient
510 glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
511 glDisable(GL_COLOR_MATERIAL);
512
513 // Simplest and fastest drawing is default
514 glShadeModel(GL_FLAT);
515 glDisable(GL_BLEND);
516 glDisable(GL_LINE_SMOOTH);
517 glDisable(GL_POINT_SMOOTH);
518 glDisable(GL_COLOR_MATERIAL);
519
520 // Lighting
521 glDisable(GL_LIGHTING);
522
523 // No normalization of normals (it's broken on some machines anyway)
524 glDisable(GL_NORMALIZE);
525
526 // Dithering if needed
527 glDisable(GL_DITHER);
528 makeNonCurrent();
529 }
530 #endif
531 }
532
533
534 // Render all the graphics into a world box
drawWorld(FXViewport & wv)535 void FXGLViewer::drawWorld(FXViewport& wv){
536 #ifdef HAVE_GL_H
537
538 // Set viewport
539 glViewport(0,0,wv.w,wv.h);
540
541 // Reset important stuff
542 glShadeModel(GL_SMOOTH);
543 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
544 glDisable(GL_LIGHTING);
545 glDisable(GL_ALPHA_TEST);
546 glDisable(GL_BLEND);
547 glDisable(GL_DITHER);
548 glDisable(GL_FOG);
549 glDisable(GL_LOGIC_OP);
550 glDisable(GL_POLYGON_SMOOTH);
551 glDisable(GL_POLYGON_STIPPLE);
552 glDisable(GL_STENCIL_TEST);
553 glDisable(GL_CULL_FACE);
554 glDisable(GL_COLOR_MATERIAL);
555
556 // Reset matrices
557 glMatrixMode(GL_PROJECTION);
558 glLoadIdentity();
559 glMatrixMode(GL_MODELVIEW);
560 glLoadIdentity();
561
562 // Clear to solid background
563 glClearDepth(1.0);
564 glClearColor(background[0][0],background[0][1],background[0][2],background[0][3]);
565 if(background[0]==background[1]){
566 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
567 }
568
569 // Clear to gradient background
570 else{
571 glClear(GL_DEPTH_BUFFER_BIT);
572 glDisable(GL_DEPTH_TEST);
573 glDepthMask(GL_FALSE);
574 glBegin(GL_TRIANGLE_STRIP);
575 glColor4fv(background[1]); glVertex3f(-1.0f,-1.0f,0.0f); glVertex3f( 1.0f,-1.0f,0.0f);
576 glColor4fv(background[0]); glVertex3f(-1.0f, 1.0f,0.0f); glVertex3f( 1.0f, 1.0f,0.0f);
577 glEnd();
578 }
579
580 // Depth test on by default
581 glDepthMask(GL_TRUE);
582 glEnable(GL_DEPTH_TEST);
583
584 // Switch to projection matrix
585 glMatrixMode(GL_PROJECTION);
586 glLoadIdentity();
587 switch(projection){
588 case PARALLEL:
589 glOrtho(wv.left,wv.right,wv.bottom,wv.top,wv.hither,wv.yon);
590 break;
591 case PERSPECTIVE:
592 glFrustum(wv.left,wv.right,wv.bottom,wv.top,wv.hither,wv.yon);
593 break;
594 }
595
596 // Switch to model matrix
597 glMatrixMode(GL_MODELVIEW);
598 glLoadIdentity();
599
600 // Set light parameters
601 glEnable(GL_LIGHT0);
602 glLightfv(GL_LIGHT0,GL_AMBIENT,light.ambient);
603 glLightfv(GL_LIGHT0,GL_DIFFUSE,light.diffuse);
604 glLightfv(GL_LIGHT0,GL_SPECULAR,light.specular);
605 glLightfv(GL_LIGHT0,GL_POSITION,light.position);
606 glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,light.direction);
607 glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,light.exponent);
608 glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,light.cutoff);
609 glLightf(GL_LIGHT0,GL_CONSTANT_ATTENUATION,light.c_attn);
610 glLightf(GL_LIGHT0,GL_LINEAR_ATTENUATION,light.l_attn);
611 glLightf(GL_LIGHT0,GL_QUADRATIC_ATTENUATION,light.q_attn);
612
613 // Default material colors
614 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,material.ambient);
615 glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,material.diffuse);
616 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,material.specular);
617 glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,material.emission);
618 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,material.shininess);
619
620 // Color commands change both
621 glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
622
623 // Global ambient light
624 glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient);
625
626 // Enable fog
627 if(options&VIEWER_FOG){
628 glEnable(GL_FOG);
629 glFogfv(GL_FOG_COLOR,background[0]); // Disappear into the background
630 //glFogf(GL_FOG_DENSITY,1.0f);
631 glFogf(GL_FOG_START,(GLfloat)(distance-diameter)); // Range tight around model position
632 glFogf(GL_FOG_END,(GLfloat)(distance+diameter)); // Far place same as clip plane:- clipped stuff is in the mist!
633 glFogi(GL_FOG_MODE,GL_LINEAR); // Simple linear depth cueing
634 }
635
636 // Dithering
637 if(options&VIEWER_DITHER){
638 glEnable(GL_DITHER);
639 }
640
641 // Enable lighting
642 if(options&VIEWER_LIGHTING){
643 glEnable(GL_LIGHTING);
644 }
645
646 // Set model matrix
647 glLoadMatrixf(transform);
648
649 // Draw what's visible
650 if(scene) scene->draw(this);
651 #endif
652 }
653
654
655 // Render with anti-aliasing
drawAnti(FXViewport & wv)656 void FXGLViewer::drawAnti(FXViewport& wv){
657 #ifdef HAVE_GL_H
658 FXViewport jt=wv;
659 FXdouble d=0.5*worldpx;
660 register FXuint i;
661 glClearAccum(0.0f,0.0f,0.0f,0.0f);
662 glClear(GL_ACCUM_BUFFER_BIT);
663 for(i=0; i<ARRAYNUMBER(jitter); i++){
664 jt.left = wv.left+jitter[i][0]*d;
665 jt.right = wv.right+jitter[i][0]*d;
666 jt.top = wv.top+jitter[i][1]*d;
667 jt.bottom = wv.bottom+jitter[i][1]*d;
668 drawWorld(jt);
669 glAccum(GL_ACCUM,1.0/ARRAYNUMBER(jitter));
670 }
671 glAccum(GL_RETURN,1.0);
672 #endif
673 }
674
675
676 // Fill select buffer with hits in rectangle
selectHits(FXuint * & hits,FXint & nhits,FXint x,FXint y,FXint w,FXint h)677 FXint FXGLViewer::selectHits(FXuint*& hits,FXint& nhits,FXint x,FXint y,FXint w,FXint h){
678 #ifdef HAVE_GL_H
679 register FXfloat pickx,picky,pickw,pickh;
680 register FXint mh=maxhits;
681 hits=NULL;
682 nhits=0;
683 if(makeCurrent()){
684
685 // Where to pick
686 pickx=(wvt.w-2.0f*x-w)/((FXfloat)w);
687 picky=(2.0f*y+h-wvt.h)/((FXfloat)h);
688 pickw=wvt.w/((FXfloat)w);
689 pickh=wvt.h/((FXfloat)h);
690
691 // Set pick projection matrix
692 glMatrixMode(GL_PROJECTION);
693 glLoadIdentity();
694 glTranslatef(pickx,picky,0.0f);
695 glScalef(pickw,pickh,1.0f);
696 switch(projection){
697 case PARALLEL:
698 glOrtho(wvt.left,wvt.right,wvt.bottom,wvt.top,wvt.hither,wvt.yon);
699 break;
700 case PERSPECTIVE:
701 glFrustum(wvt.left,wvt.right,wvt.bottom,wvt.top,wvt.hither,wvt.yon);
702 break;
703 }
704
705 // Model matrix
706 glMatrixMode(GL_MODELVIEW);
707 glLoadMatrixf(transform);
708
709 // Loop until room enough to fit
710 do{
711 nhits=0;
712 if(!FXRESIZE(&hits,FXuint,mh)) break;
713 glSelectBuffer(mh,(GLuint*)hits);
714 glRenderMode(GL_SELECT);
715 glInitNames();
716 glPushName(0);
717 if(scene) scene->hit(this);
718 glPopName();
719 nhits=glRenderMode(GL_RENDER);
720 mh<<=1;
721 }
722 while(nhits<0);
723 makeNonCurrent();
724 if(!nhits) FXFREE(&hits);
725 return nhits;
726 }
727 #endif
728 return 0;
729 }
730
731
732 // Process picks
processHits(FXuint * pickbuffer,FXint nhits)733 FXGLObject* FXGLViewer::processHits(FXuint *pickbuffer,FXint nhits){
734 FXuint d1,d2,i,n,zmin,zmax,sel=0;
735 if(0<=nhits){
736 for(i=0,zmin=zmax=4294967295U; nhits>0; i+=n+3,nhits--){
737 n=pickbuffer[i];
738 d1=pickbuffer[1+i];
739 d2=pickbuffer[2+i];
740 if(d1<zmin || (d1==zmin && d2<=zmax)){
741 zmin=d1;
742 zmax=d2;
743 sel=i;
744 }
745 }
746 return scene->identify(&pickbuffer[4+sel]);
747 }
748 return NULL;
749 }
750
751
752 // Build NULL-terminated list of ALL picked objects overlapping rectangle
select(FXint x,FXint y,FXint w,FXint h)753 FXGLObject** FXGLViewer::select(FXint x,FXint y,FXint w,FXint h){
754 FXGLObject *obj,**objects=NULL;
755 FXint nhits,i,j;
756 FXuint *hits;
757 if(scene && maxhits){
758 if(selectHits(hits,nhits,x,y,w,h)){ // FIXME leak
759 FXMALLOC(&objects,FXGLObject*,nhits+1);
760 for(i=j=0; nhits>0; i+=hits[i]+3,nhits--){
761 if((obj=scene->identify(&hits[4+i]))!=NULL) objects[j++]=obj;
762 }
763 objects[j]=NULL;
764 FXFREE(&hits);
765 }
766 }
767 return objects;
768 }
769
770
771 // Lasso objects
lasso(FXint x1,FXint y1,FXint x2,FXint y2)772 FXGLObject** FXGLViewer::lasso(FXint x1,FXint y1,FXint x2,FXint y2){
773 FXint xlo,xhi,ylo,yhi;
774 FXMINMAX(xlo,xhi,x1,x2);
775 FXMINMAX(ylo,yhi,y1,y2);
776 return select(xlo,ylo,xhi-xlo+1,yhi-ylo+1);
777 }
778
779
780 // Pick ONE object at x,y
pick(FXint x,FXint y)781 FXGLObject* FXGLViewer::pick(FXint x,FXint y){
782 FXGLObject *obj=NULL;
783 FXuint *hits;
784 FXint nhits;
785 if(scene && maxhits){
786 if(selectHits(hits,nhits,x-PICK_TOL,y-PICK_TOL,PICK_TOL*2,PICK_TOL*2)){ // FIXME leak
787 obj=processHits(hits,nhits);
788 FXFREE(&hits);
789 }
790 }
791 return obj;
792 }
793
794
795 // Repaint the GL window
onPaint(FXObject *,FXSelector,void *)796 long FXGLViewer::onPaint(FXObject*,FXSelector,void*){
797 #ifdef HAVE_GL_H
798 FXGLVisual *vis=(FXGLVisual*)getVisual();
799 FXASSERT(xid);
800 if(makeCurrent()){
801 drawWorld(wvt);
802 if(vis->isDoubleBuffer()) swapBuffers();
803 makeNonCurrent();
804 }
805 #endif
806 return 1;
807 }
808
809
810 // Handle configure notify
layout()811 void FXGLViewer::layout(){
812 wvt.w=width;
813 wvt.h=height;
814 updateProjection();
815 flags&=~FLAG_DIRTY;
816 }
817
818
819 // Start motion timer while in this window
onEnter(FXObject * sender,FXSelector sel,void * ptr)820 long FXGLViewer::onEnter(FXObject* sender,FXSelector sel,void* ptr){
821 FXGLCanvas::onEnter(sender,sel,ptr);
822 if(isEnabled()){
823 getApp()->addTimeout(this,ID_TIPTIMER,getApp()->getMenuPause());
824 }
825 return 1;
826 }
827
828
829 // Stop motion timer when leaving window
onLeave(FXObject * sender,FXSelector sel,void * ptr)830 long FXGLViewer::onLeave(FXObject* sender,FXSelector sel,void* ptr){
831 FXGLCanvas::onLeave(sender,sel,ptr);
832 if(isEnabled()){
833 getApp()->removeTimeout(this,ID_TIPTIMER);
834 }
835 return 1;
836 }
837
838
839 // Gained focus
onFocusIn(FXObject * sender,FXSelector sel,void * ptr)840 long FXGLViewer::onFocusIn(FXObject* sender,FXSelector sel,void* ptr){
841 FXGLCanvas::onFocusIn(sender,sel,ptr);
842 if(selection && selection->handle(this,FXSEL(SEL_FOCUSIN,0),ptr)){
843 update();
844 }
845 return 1;
846 }
847
848
849 // Lost focus
onFocusOut(FXObject * sender,FXSelector sel,void * ptr)850 long FXGLViewer::onFocusOut(FXObject* sender,FXSelector sel,void* ptr){
851 FXGLCanvas::onFocusOut(sender,sel,ptr);
852 if(selection && selection->handle(this,FXSEL(SEL_FOCUSOUT,0),ptr)){
853 update();
854 }
855 return 1;
856 }
857
858
859 // Change scene
setScene(FXGLObject * sc)860 void FXGLViewer::setScene(FXGLObject* sc){
861 scene=sc;
862 update();
863 }
864
865
866 // Change field of view
setFieldOfView(FXdouble fv)867 void FXGLViewer::setFieldOfView(FXdouble fv){
868 FXdouble tn;
869 fov=FXCLAMP(2.0,fv,90.0);
870 tn=tan(0.5*DTOR*fov);
871 FXASSERT(tn>0.0);
872 distance=diameter/tn;
873 FXASSERT(distance>0.0);
874 updateProjection();
875 updateTransform();
876 update();
877 }
878
879
880 // Change eye distance
setDistance(FXdouble d)881 void FXGLViewer::setDistance(FXdouble d){
882 if(d<diameter) d=diameter;
883 if(d>114.0*diameter) d=114.0*diameter;
884 if(d!=distance){
885 distance=d;
886 FXASSERT(distance>0.0);
887 fov=2.0*RTOD*atan2(diameter,distance);
888 updateProjection();
889 updateTransform();
890 update();
891 }
892 }
893
894
895 // Change zoom factor
setZoom(FXdouble zm)896 void FXGLViewer::setZoom(FXdouble zm){
897 if(zm<1.0E-30) zm=1.0E-30;
898 if(zm!=zoom){
899 zoom=zm;
900 updateProjection();
901 update();
902 }
903 }
904
905
906 // Change scale factors
setScale(FXVec3f s)907 void FXGLViewer::setScale(FXVec3f s){
908 if(s.x<0.000001f) s.x=0.000001f;
909 if(s.y<0.000001f) s.y=0.000001f;
910 if(s.z<0.000001f) s.z=0.000001f;
911 if(scale!=s){
912 scale=s;
913 updateTransform();
914 update();
915 }
916 }
917
918
919 // Change orientation to new quaternion
setOrientation(FXQuatf rot)920 void FXGLViewer::setOrientation(FXQuatf rot){
921 if(rot!=rotation){
922 rotation=rot;
923 rotation.adjust();
924 updateTransform();
925 update();
926 }
927 }
928
929
930 // Change world projection
updateProjection()931 void FXGLViewer::updateProjection(){
932 FXdouble hither_fac,r,aspect;
933
934 // Should be non-0 size viewport
935 if(wvt.w>0 && wvt.h>0){
936
937 // Aspect ratio of viewer
938 aspect = (FXdouble)wvt.h / (FXdouble)wvt.w;
939
940 // Get world box
941 r=0.5*diameter/zoom;
942 if(wvt.w<=wvt.h){
943 wvt.left=-r;
944 wvt.right=r;
945 wvt.bottom=-r*aspect;
946 wvt.top=r*aspect;
947 }
948 else{
949 wvt.left=-r/aspect;
950 wvt.right=r/aspect;
951 wvt.bottom=-r;
952 wvt.top=r;
953 }
954 FXASSERT(distance>0.0);
955 FXASSERT(diameter>0.0);
956
957 // A more intelligent method for setting the
958 // clip planes might be interesting...
959 wvt.yon=distance+diameter;
960 wvt.hither=0.1*wvt.yon;
961 //wvt.hither=distance-diameter;
962 // if(wvt.hither<distance-diameter) wvt.hither=distance-diameter;
963
964 // New window
965 FXTRACE((100,"wvt.left=%g wvt.right=%g wvt.top=%g wvt.bottom=%g wvt.hither=%g wvt.yon=%g\n",wvt.left,wvt.right,wvt.top,wvt.bottom,wvt.hither,wvt.yon));
966
967 // Size of a pixel in world and model
968 worldpx=(wvt.right-wvt.left)/wvt.w;
969 modelpx=worldpx*diameter;
970
971 // Precalc stuff for view->world backmapping
972 ax=wvt.left;
973 ay=wvt.top-worldpx;
974
975 // Report factors
976 FXTRACE((100,"worldpx=%g modelpx=%g\n",worldpx,modelpx));
977
978 // Correction for perspective
979 if(projection==PERSPECTIVE){
980 FXASSERT(distance>0.0);
981 hither_fac=wvt.hither/distance;
982 wvt.left*=hither_fac;
983 wvt.right*=hither_fac;
984 wvt.top*=hither_fac;
985 wvt.bottom*=hither_fac;
986 }
987 }
988 }
989
990
991 // Change transformation matrix
updateTransform()992 void FXGLViewer::updateTransform(){
993 transform.eye();
994 transform.trans(0.0f,0.0f,(FXfloat)-distance);
995 transform.rot(rotation);
996 transform.scale(scale);
997 transform.trans(-center);
998 itransform=transform.invert();
999 // FXTRACE((150,"itrans=%11.8f %11.8f %11.8f %11.8f\n",itransform[0][0],itransform[0][1],itransform[0][2],itransform[0][3]));
1000 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",itransform[1][0],itransform[1][1],itransform[1][2],itransform[1][3]));
1001 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",itransform[2][0],itransform[2][1],itransform[2][2],itransform[2][3]));
1002 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",itransform[3][0],itransform[3][1],itransform[3][2],itransform[3][3]));
1003 // FXTRACE((150,"\n"));
1004 // FXTRACE((150," trans=%11.8f %11.8f %11.8f %11.8f\n",transform[0][0],transform[0][1],transform[0][2],transform[0][3]));
1005 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",transform[1][0],transform[1][1],transform[1][2],transform[1][3]));
1006 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",transform[2][0],transform[2][1],transform[2][2],transform[2][3]));
1007 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",transform[3][0],transform[3][1],transform[3][2],transform[3][3]));
1008 // FXTRACE((150,"\n"));
1009 // FXHMat check=itransform*transform;
1010 // FXTRACE((150," check=%11.8f %11.8f %11.8f %11.8f\n",check[0][0],check[0][1],check[0][2],check[0][3]));
1011 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",check[1][0],check[1][1],check[1][2],check[1][3]));
1012 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",check[2][0],check[2][1],check[2][2],check[2][3]));
1013 // FXTRACE((150," %11.8f %11.8f %11.8f %11.8f\n",check[3][0],check[3][1],check[3][2],check[3][3]));
1014 // FXTRACE((150,"\n"));
1015 }
1016
1017
1018 // Set model bounding box
setBounds(const FXRangef & r)1019 FXbool FXGLViewer::setBounds(const FXRangef& r){
1020 // FXTRACE((100,"xlo=%g xhi=%g ylo=%g yhi=%g zlo=%g zhi=%g\n",r.lower.x,r.upper.x,r.lower.y,r.upper.y,r.lower.z,r.upper.z));
1021
1022 // Model center
1023 center=r.center();
1024
1025 // Model size
1026 diameter=r.longest();
1027
1028 // Fix zero size model
1029 if(diameter<1.0E-30) diameter=1.0;
1030
1031 // Set equal scaling initially
1032 scale=FXVec3f(1.0f,1.0f,1.0f);
1033
1034 // Reset distance (and thus field of view)
1035 setDistance(1.1*diameter);
1036
1037 return TRUE;
1038 }
1039
1040
1041 // Fit view to new bounds
fitToBounds(const FXRangef & box)1042 FXbool FXGLViewer::fitToBounds(const FXRangef& box){
1043 FXRangef r(FLT_MAX,-FLT_MAX,FLT_MAX,-FLT_MAX,FLT_MAX,-FLT_MAX);
1044 FXMat4f m;
1045
1046 // Get rotation of model
1047 m.eye();
1048 m.rot(rotation);
1049 m.trans(-box.center());
1050
1051 // Transform box
1052 for(int i=0; i<8; i++){
1053 r.include(box.corner(i)*m);
1054 }
1055
1056 setBounds(r);
1057 return TRUE;
1058 }
1059
1060
1061 // Obtain viewport
getViewport(FXViewport & v) const1062 void FXGLViewer::getViewport(FXViewport& v) const {
1063 v=wvt;
1064 }
1065
1066
1067 // Set material
setMaterial(const FXMaterial & mtl)1068 void FXGLViewer::setMaterial(const FXMaterial &mtl){
1069 material=mtl;
1070 update();
1071 }
1072
1073
1074 // Get material
getMaterial(FXMaterial & mtl) const1075 void FXGLViewer::getMaterial(FXMaterial &mtl) const {
1076 mtl=material;
1077 }
1078
1079
1080 // Get screen point from eye coordinate
eyeToScreen(FXint & sx,FXint & sy,FXVec3f e)1081 void FXGLViewer::eyeToScreen(FXint& sx,FXint& sy,FXVec3f e){
1082 register double xp,yp;
1083 if(projection==PERSPECTIVE){
1084 if(e.z==0.0f){ fxerror("%s::eyeToScreen: cannot transform point.\n",getClassName()); }
1085 xp=-distance*e.x/e.z;
1086 yp=-distance*e.y/e.z;
1087 }
1088 else{
1089 xp=e.x;
1090 yp=e.y;
1091 }
1092 sx=(int)((xp-ax)/worldpx);
1093 sy=(int)((ay-yp)/worldpx);
1094 }
1095
1096
1097 // Convert screen point to eye coords
screenToEye(FXint sx,FXint sy,FXfloat eyez)1098 FXVec3f FXGLViewer::screenToEye(FXint sx,FXint sy,FXfloat eyez){
1099 register float xp,yp;
1100 FXVec3f e;
1101 xp=(float)(worldpx*sx+ax);
1102 yp=(float)(ay-worldpx*sy);
1103 if(projection==PERSPECTIVE){
1104 FXASSERT(distance>0.0);
1105 e.x=(FXfloat)(-eyez*xp/distance);
1106 e.y=(FXfloat)(-eyez*yp/distance);
1107 e.z=eyez;
1108 }
1109 else{
1110 e.x=xp;
1111 e.y=yp;
1112 e.z=eyez;
1113 }
1114 return e;
1115 }
1116
1117
1118 // Convert screen to eye, on projection plane
screenToTarget(FXint sx,FXint sy)1119 FXVec3f FXGLViewer::screenToTarget(FXint sx,FXint sy){
1120 return FXVec3f((FXfloat)(worldpx*sx+ax), (FXfloat)(ay-worldpx*sy), (FXfloat)-distance);
1121 }
1122
1123
1124 // Convert world to eye coords
worldToEye(FXVec3f w)1125 FXVec3f FXGLViewer::worldToEye(FXVec3f w){
1126 return w*transform;
1127 }
1128
1129
1130 // Get eye Z-coordinate of world point
worldToEyeZ(FXVec3f w)1131 FXfloat FXGLViewer::worldToEyeZ(FXVec3f w){
1132 return w.x*transform[0][2]+w.y*transform[1][2]+w.z*transform[2][2]+transform[3][2];
1133 }
1134
1135
1136 // Convert eye to world coords
eyeToWorld(FXVec3f e)1137 FXVec3f FXGLViewer::eyeToWorld(FXVec3f e){
1138 return e*itransform;
1139 }
1140
1141
1142 // Get world vector
worldVector(FXint fx,FXint fy,FXint tx,FXint ty)1143 FXVec3f FXGLViewer::worldVector(FXint fx,FXint fy,FXint tx,FXint ty){
1144 FXVec3f wfm,wto,vec;
1145 wfm=screenToTarget(fx,fy);
1146 wto=screenToTarget(tx,ty);
1147 vec=wto*itransform-wfm*itransform;
1148 return vec;
1149 }
1150
1151
1152 // Get a bore vector
getBoreVector(FXint sx,FXint sy,FXVec3f & point,FXVec3f & dir)1153 FXbool FXGLViewer::getBoreVector(FXint sx,FXint sy,FXVec3f& point,FXVec3f& dir){
1154 FXVec3f p=eyeToWorld(screenToEye(sx,sy,(FXfloat)(diameter-distance)));
1155 if(PARALLEL==projection)
1156 point=eyeToWorld(screenToEye(sx,sy,0.0f));
1157 else
1158 point=eyeToWorld(FXVec3f(0.0f,0.0f,0.0f));
1159 dir=normalize(p-point);
1160 return TRUE;
1161 }
1162
1163
1164 // Get eye viewing direction (non-normalized)
getEyeVector() const1165 FXVec3f FXGLViewer::getEyeVector() const {
1166 return FXVec3f(-itransform[2][0],-itransform[2][1],-itransform[2][2]);
1167 }
1168
1169
1170 // Get eye position
getEyePosition() const1171 FXVec3f FXGLViewer::getEyePosition() const{
1172 return FXVec3f(itransform[3][0],itransform[3][1],itransform[3][2]);
1173 }
1174
1175
1176 // Change model center
setCenter(FXVec3f cntr)1177 void FXGLViewer::setCenter(FXVec3f cntr){
1178 if(center!=cntr){
1179 center=cntr;
1180 updateTransform();
1181 update();
1182 }
1183 }
1184
1185
1186 // Translate in world
translate(FXVec3f vec)1187 void FXGLViewer::translate(FXVec3f vec){
1188 center+=vec;
1189 updateTransform();
1190 update();
1191 }
1192
1193
1194 // Change selection
setSelection(FXGLObject * sel)1195 void FXGLViewer::setSelection(FXGLObject* sel){
1196 if(selection!=sel){
1197 selection=sel;
1198 update();
1199 }
1200 }
1201
1202
1203 // Change help text
setHelpText(const FXString & text)1204 void FXGLViewer::setHelpText(const FXString& text){
1205 help=text;
1206 }
1207
1208
1209 // Change tip text
setTipText(const FXString & text)1210 void FXGLViewer::setTipText(const FXString& text){
1211 tip=text;
1212 }
1213
1214
1215 // Translate point into unit-sphere coordinate
spherePoint(FXint px,FXint py)1216 FXVec3f FXGLViewer::spherePoint(FXint px,FXint py){
1217 FXfloat d,t,screenmin;
1218 FXVec3f v;
1219 if(wvt.w>wvt.h)
1220 screenmin=(FXfloat)wvt.h;
1221 else
1222 screenmin=(FXfloat)wvt.w;
1223 v.x=2.0f*(px-0.5f*wvt.w)/screenmin;
1224 v.y=2.0f*(0.5f*wvt.h-py)/screenmin;
1225 d=v.x*v.x+v.y*v.y;
1226 if(d<0.75){
1227 v.z=sqrtf(1.0-d);
1228 }
1229 else if(d<3.0f){
1230 d=1.7320508008f-sqrtf(d);
1231 t=1.0f-d*d;
1232 if(t<0.0f) t=0.0f;
1233 v.z=1.0f-sqrtf(t);
1234 }
1235 else{
1236 v.z=0.0f;
1237 }
1238 return normalize(v);
1239 }
1240
1241
1242 // Turn camera; simpler now that arc() is changed
turn(FXint fx,FXint fy,FXint tx,FXint ty)1243 FXQuatf FXGLViewer::turn(FXint fx,FXint fy,FXint tx,FXint ty){
1244 return FXQuatf(spherePoint(fx,fy),spherePoint(tx,ty));
1245 }
1246
1247
1248 // Draw non-destructive lasso box; drawing twice will erase it again
drawLasso(FXint x0,FXint y0,FXint x1,FXint y1)1249 void FXGLViewer::drawLasso(FXint x0,FXint y0,FXint x1,FXint y1){
1250 #ifdef HAVE_GL_H
1251 FXGLVisual *vis=(FXGLVisual*)getVisual();
1252
1253 // With OpenGL, first change back to 1:1 projection mode
1254 if(makeCurrent()){
1255
1256 // Save state
1257 glPushAttrib(GL_COLOR_BUFFER_BIT|GL_ENABLE_BIT|GL_DEPTH_BUFFER_BIT|GL_LINE_BIT);
1258 glMatrixMode(GL_MODELVIEW);
1259 glPushMatrix();
1260 glLoadIdentity();
1261 glMatrixMode(GL_PROJECTION);
1262 glPushMatrix();
1263
1264 // Fix xform
1265 glLoadIdentity();
1266 glOrtho(0.0,width-1.0,0.0,height-1.0,0.0,1.0);
1267
1268 // Draw in front buffer, so we see it w/o blowing
1269 // away the drawing by calling swapBuffers.
1270 if(vis->isDoubleBuffer()) glDrawBuffer(GL_FRONT);
1271
1272 // Fancy stuff off
1273 glLineWidth(1.0);
1274 glDisable(GL_DEPTH_TEST);
1275 glDisable(GL_COLOR_MATERIAL);
1276 glDisable(GL_LIGHTING);
1277 glShadeModel(GL_FLAT);
1278 glDepthMask(FALSE);
1279 glDisable(GL_DITHER);
1280
1281 // Windows
1282 #ifdef WIN32
1283
1284 #ifndef _ALPHA_
1285 // MS-Windows has logic ops, and they seem to work:- at least
1286 // with the unaccelerated software rendering they seem to...
1287 glEnable(GL_COLOR_LOGIC_OP);
1288 glLogicOp(GL_INVERT);
1289
1290 #else
1291 // ALPHA CPU's don't have logic ops; or at least they're broken :-(
1292 glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);
1293 glEnable(GL_BLEND);
1294
1295 #endif
1296
1297 // UNIX
1298 #else
1299 #if !defined(GL_VERSION_1_1) || !defined(GL_VERSION_1_2)
1300
1301 // If you don't have OpenGL 1.1 or better, blending
1302 // to invert the lasso is your only choice...
1303 glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);
1304 glEnable(GL_BLEND);
1305
1306 #else
1307
1308 // You have OpenGL 1.1 or better, but chances are it
1309 // still doesn't work, because you may have an incomplete
1310 // implementation [DEC], or perhaps broken hardware.
1311
1312 // If it works for you, uncomment the lines below,
1313 // and comment the ones above...
1314 glEnable(GL_COLOR_LOGIC_OP);
1315 glLogicOp(GL_INVERT);
1316 #endif
1317 #endif
1318
1319 glBegin(GL_LINE_LOOP);
1320 glColor4ub(255,255,255,255);
1321 glVertex2i(x0,wvt.h-y0-1);
1322 glVertex2i(x0,wvt.h-y1-1);
1323 glVertex2i(x1,wvt.h-y1-1);
1324 glVertex2i(x1,wvt.h-y0-1);
1325 glEnd();
1326 glFinish(); // Moved back here because of driver issues
1327
1328 // Restore to old state
1329 glPopMatrix();
1330 glMatrixMode(GL_MODELVIEW);
1331 glPopMatrix();
1332 glPopAttrib();
1333 makeNonCurrent();
1334 }
1335 #endif
1336 }
1337
1338 /************************* Mouse Actions in Viewer ***************************/
1339
1340
1341 // Current object changed
onChanged(FXObject *,FXSelector,void * ptr)1342 long FXGLViewer::onChanged(FXObject*,FXSelector,void* ptr){
1343 setSelection((FXGLObject*)ptr);
1344 if(target) target->tryHandle(this,FXSEL(SEL_CHANGED,message),ptr);
1345 return 1;
1346 }
1347
1348
1349 // Message that indicates where user picked
onPick(FXObject *,FXSelector,void * ptr)1350 long FXGLViewer::onPick(FXObject*,FXSelector,void* ptr){
1351 return target && target->tryHandle(this,FXSEL(SEL_PICKED,message),ptr);
1352 }
1353
1354
1355 // Clicked in widget
onClicked(FXObject *,FXSelector,void * ptr)1356 long FXGLViewer::onClicked(FXObject*,FXSelector,void* ptr){
1357 if(target){
1358 if(target->tryHandle(this,FXSEL(SEL_CLICKED,message),ptr)) return 1;
1359 if(ptr && target->tryHandle(this,FXSEL(SEL_COMMAND,message),ptr)) return 1;
1360 }
1361 return 1;
1362 }
1363
1364
1365 // Double clicked in widget; ptr may or may not point to an object
onDoubleClicked(FXObject *,FXSelector,void * ptr)1366 long FXGLViewer::onDoubleClicked(FXObject*,FXSelector,void* ptr){
1367 return target && target->tryHandle(this,FXSEL(SEL_DOUBLECLICKED,message),ptr);
1368 }
1369
1370
1371 // Triple clicked in widget; ptr may or may not point to an object
onTripleClicked(FXObject *,FXSelector,void * ptr)1372 long FXGLViewer::onTripleClicked(FXObject*,FXSelector,void* ptr){
1373 return target && target->tryHandle(this,FXSEL(SEL_TRIPLECLICKED,message),ptr);
1374 }
1375
1376
1377 // Lassoed object(s)
onLassoed(FXObject *,FXSelector,void * ptr)1378 long FXGLViewer::onLassoed(FXObject*,FXSelector,void* ptr){
1379 FXEvent* event=(FXEvent*)ptr;
1380 FXGLObject **objlist;
1381
1382 // Notify target of lasso
1383 if(target && target->tryHandle(this,FXSEL(SEL_LASSOED,message),ptr)) return 1;
1384
1385 // Grab all objects in lasso
1386 objlist=lasso(event->click_x,event->click_y,event->win_x,event->win_y);
1387
1388 // Add selection mode
1389 if(event->state&SHIFTMASK){
1390 handle(this,FXSEL(SEL_SELECTED,0),(void*)objlist);
1391 }
1392
1393 // Toggle selection mode
1394 else if(event->state&CONTROLMASK){
1395 handle(this,FXSEL(SEL_DESELECTED,0),(void*)objlist);
1396 }
1397
1398 // Free list
1399 FXFREE(&objlist);
1400
1401 return 1;
1402 }
1403
1404
1405 // Selected object(s)
onSelected(FXObject *,FXSelector,void * ptr)1406 long FXGLViewer::onSelected(FXObject*,FXSelector,void* ptr){
1407 return target && target->tryHandle(this,FXSEL(SEL_SELECTED,message),ptr);
1408 }
1409
1410
1411 // Deselected object(s)
onDeselected(FXObject *,FXSelector,void * ptr)1412 long FXGLViewer::onDeselected(FXObject*,FXSelector,void* ptr){
1413 return target && target->tryHandle(this,FXSEL(SEL_DESELECTED,message),ptr);
1414 }
1415
1416
1417 // Inserted object(s)
onInserted(FXObject *,FXSelector,void * ptr)1418 long FXGLViewer::onInserted(FXObject*,FXSelector,void* ptr){
1419 return target && target->tryHandle(this,FXSEL(SEL_INSERTED,message),ptr);
1420 }
1421
1422
1423 // Deleted object(s)
onDeleted(FXObject *,FXSelector,void * ptr)1424 long FXGLViewer::onDeleted(FXObject*,FXSelector,void* ptr){
1425 return target && target->tryHandle(this,FXSEL(SEL_DELETED,message),ptr);
1426 }
1427
1428
1429 // Change operation
setOp(FXuint o)1430 void FXGLViewer::setOp(FXuint o){
1431 if(mode!=o){
1432 switch(o){
1433 case HOVERING:
1434 setDragCursor(getDefaultCursor());
1435 FXTRACE((100,"HOVERING\n"));
1436 if(doesturbo) update();
1437 doesturbo=FALSE;
1438 break;
1439 case PICKING:
1440 FXTRACE((100,"PICKING\n"));
1441 setDragCursor(getDefaultCursor());
1442 break;
1443 case ROTATING:
1444 FXTRACE((100,"ROTATING\n"));
1445 doesturbo=turbomode;
1446 setDragCursor(getApp()->getDefaultCursor(DEF_ROTATE_CURSOR));
1447 break;
1448 case POSTING:
1449 FXTRACE((100,"POSTING\n"));
1450 setDragCursor(getDefaultCursor());
1451 break;
1452 case TRANSLATING:
1453 FXTRACE((100,"TRANSLATING\n"));
1454 doesturbo=turbomode;
1455 setDragCursor(getApp()->getDefaultCursor(DEF_MOVE_CURSOR));
1456 break;
1457 case ZOOMING:
1458 FXTRACE((100,"ZOOMING\n"));
1459 doesturbo=turbomode;
1460 setDragCursor(getApp()->getDefaultCursor(DEF_DRAGH_CURSOR));
1461 break;
1462 case FOVING:
1463 FXTRACE((100,"FOVING\n"));
1464 doesturbo=turbomode;
1465 setDragCursor(getApp()->getDefaultCursor(DEF_DRAGH_CURSOR));
1466 break;
1467 case DRAGGING:
1468 FXTRACE((100,"DRAGGING\n"));
1469 doesturbo=turbomode;
1470 setDragCursor(getApp()->getDefaultCursor(DEF_MOVE_CURSOR));
1471 break;
1472 case TRUCKING:
1473 FXTRACE((100,"TRUCKING\n"));
1474 doesturbo=turbomode;
1475 setDragCursor(getApp()->getDefaultCursor(DEF_DRAGH_CURSOR));
1476 break;
1477 case GYRATING:
1478 FXTRACE((100,"GYRATING\n"));
1479 doesturbo=turbomode;
1480 setDragCursor(getApp()->getDefaultCursor(DEF_ROTATE_CURSOR));
1481 break;
1482 case DO_LASSOSELECT:
1483 if(mode==LASSOSELECT) return;
1484 FXTRACE((100,"LASSOSELECT\n"));
1485 setDefaultCursor(getApp()->getDefaultCursor(DEF_CORNERNW_CURSOR));
1486 /// FIXME grab
1487 break;
1488 case LASSOSELECT:
1489 FXTRACE((100,"LASSOSELECT\n"));
1490 setDefaultCursor(getDragCursor());
1491 setDragCursor(getApp()->getDefaultCursor(DEF_CORNERNW_CURSOR));
1492 break;
1493 case DO_LASSOZOOM:
1494 if(mode==LASSOZOOM) return;
1495 FXTRACE((100,"LASSOZOOM\n"));
1496 setDefaultCursor(getApp()->getDefaultCursor(DEF_CORNERNW_CURSOR));
1497 /// FIXME grab
1498 break;
1499 case LASSOZOOM:
1500 FXTRACE((100,"LASSOZOOM\n"));
1501 setDefaultCursor(getDragCursor());
1502 setDragCursor(getApp()->getDefaultCursor(DEF_CORNERNW_CURSOR));
1503 break;
1504 }
1505 mode=o;
1506 }
1507 }
1508
1509
1510 // Perform the usual mouse manipulation
onLeftBtnPress(FXObject *,FXSelector,void * ptr)1511 long FXGLViewer::onLeftBtnPress(FXObject*,FXSelector,void* ptr){
1512 FXEvent* event=(FXEvent*)ptr;
1513 flags&=~FLAG_TIP;
1514 FXTRACE((100,"onLeftBtnPress Mask=%08x\n",event->state));
1515 handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
1516 if(isEnabled()){
1517 grab();
1518 flags&=~FLAG_UPDATE;
1519 if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONPRESS,message),ptr)) return 1;
1520 if(event->state&RIGHTBUTTONMASK){
1521 if(event->state&SHIFTMASK)
1522 setOp(TRUCKING);
1523 else
1524 setOp(ZOOMING);
1525 }
1526 else if(event->state&MIDDLEBUTTONMASK){
1527 setOp(ROTATING);
1528 }
1529 else if(mode==DO_LASSOZOOM){
1530 if(0<=event->click_x && 0<=event->click_y && event->click_x<width && event->click_y<height){
1531 drawLasso(event->click_x,event->click_y,event->win_x,event->win_y);
1532 setOp(LASSOZOOM);
1533 }
1534 else{
1535 getApp()->beep();
1536 }
1537 }
1538 else if(mode==DO_LASSOSELECT){
1539 if(0<=event->click_x && 0<=event->click_y && event->click_x<width && event->click_y<height){
1540 drawLasso(event->click_x,event->click_y,event->win_x,event->win_y);
1541 setOp(LASSOSELECT);
1542 }
1543 else{
1544 getApp()->beep();
1545 }
1546 }
1547 else if(event->state&(SHIFTMASK|CONTROLMASK)){
1548 setOp(PICKING);
1549 }
1550 else if(selection && selection->canDrag() && selection==pick(event->click_x,event->click_y)){
1551 setOp(DRAGGING);
1552 }
1553 else{
1554 setOp(PICKING);
1555 }
1556 }
1557 return 1;
1558 }
1559
1560
1561 // Left mouse button released
onLeftBtnRelease(FXObject *,FXSelector,void * ptr)1562 long FXGLViewer::onLeftBtnRelease(FXObject*,FXSelector,void* ptr){
1563 FXEvent* event=(FXEvent*)ptr;
1564 FXGLObject *objects[2];
1565 FXint new_x,new_y,cx,cy,xl,xh,yl,yh;
1566 FXVec3f vec;
1567 FXTRACE((100,"onLeftBtnRelease Mask=%08x\n",event->state));
1568 if(isEnabled()){
1569 ungrab();
1570 flags|=FLAG_UPDATE;
1571 if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONRELEASE,message),ptr)) return 1;
1572 if(event->state&RIGHTBUTTONMASK){
1573 if(event->state&SHIFTMASK){
1574 setOp(GYRATING);
1575 }
1576 else if(event->state&CONTROLMASK){
1577 setOp(FOVING);
1578 }
1579 else{
1580 setOp(TRANSLATING);
1581 }
1582 grab();
1583 }
1584 else if(event->state&MIDDLEBUTTONMASK){
1585 if(event->state&SHIFTMASK){
1586 setOp(TRUCKING);
1587 }
1588 else{
1589 setOp(ZOOMING);
1590 }
1591 grab();
1592 }
1593 else if(mode==LASSOZOOM){
1594 new_x=FXCLAMP(0,event->win_x,(width-1));
1595 new_y=FXCLAMP(0,event->win_y,(height-1));
1596 drawLasso(event->click_x,event->click_y,new_x,new_y);
1597 xl=FXMIN(new_x,event->click_x);
1598 xh=FXMAX(new_x,event->click_x);
1599 yl=FXMIN(new_y,event->click_y);
1600 yh=FXMAX(new_y,event->click_y);
1601 if(xh>xl && yh>yl){
1602 cx=(getWidth()-(xl+xh))/2;
1603 cy=(getHeight()-(yl+yh))/2;
1604 vec=worldVector(0,0,cx,cy);
1605 translate(-vec);
1606 setZoom(zoom*getWidth()/(xh-xl));
1607 }
1608 setOp(HOVERING);
1609 }
1610 else if(mode==LASSOSELECT){ // FIXME interpret control and shift for selection changes
1611 new_x=FXCLAMP(0,event->win_x,(width-1));
1612 new_y=FXCLAMP(0,event->win_y,(height-1));
1613 drawLasso(event->click_x,event->click_y,new_x,new_y);
1614 handle(this,FXSEL(SEL_LASSOED,0),ptr);
1615 setOp(HOVERING);
1616 }
1617 else if(mode==PICKING){ // FIXME interpret control and shift for selection changes
1618 setOp(HOVERING);
1619 if(!handle(this,FXSEL(SEL_PICKED,0),ptr)){
1620 objects[0]=pick(event->click_x,event->click_y);
1621 objects[1]=NULL;
1622 handle(this,FXSEL(SEL_CHANGED,0),(void*)objects[0]); // FIXME want multiple objects
1623 handle(this,FXSEL(SEL_SELECTED,0),(void*)objects);
1624 }
1625 }
1626 else if(mode==DRAGGING){
1627 if(target) target->tryHandle(this,FXSEL(SEL_DRAGGED,message),selection);
1628 setOp(HOVERING);
1629 }
1630 else{
1631 setOp(HOVERING);
1632 }
1633 if(event->click_count==1){
1634 handle(this,FXSEL(SEL_CLICKED,0),(void*)selection);
1635 }
1636 else if(event->click_count==2){
1637 handle(this,FXSEL(SEL_DOUBLECLICKED,0),(void*)selection);
1638 }
1639 else if(event->click_count==3){
1640 handle(this,FXSEL(SEL_TRIPLECLICKED,0),(void*)selection);
1641 }
1642 }
1643 return 1;
1644 }
1645
1646
1647 // Pressed middle mouse button
onMiddleBtnPress(FXObject *,FXSelector,void * ptr)1648 long FXGLViewer::onMiddleBtnPress(FXObject*,FXSelector,void* ptr){
1649 FXEvent* event=(FXEvent*)ptr;
1650 flags&=~FLAG_TIP;
1651 FXTRACE((100,"onMiddleBtnPress Mask=%08x\n",event->state));
1652 handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
1653 if(isEnabled()){
1654 grab();
1655 flags&=~FLAG_UPDATE;
1656 if(target && target->tryHandle(this,FXSEL(SEL_MIDDLEBUTTONPRESS,message),ptr)) return 1;
1657 if(event->state&SHIFTMASK){
1658 setOp(TRUCKING);
1659 }
1660 else{
1661 setOp(ZOOMING);
1662 }
1663 }
1664 return 1;
1665 }
1666
1667
1668 // Released middle mouse button
onMiddleBtnRelease(FXObject *,FXSelector,void * ptr)1669 long FXGLViewer::onMiddleBtnRelease(FXObject*,FXSelector,void* ptr){
1670 FXEvent* event=(FXEvent*)ptr;
1671 FXTRACE((100,"onMiddleBtnRelease Mask=%08x\n",event->state));
1672 if(isEnabled()){
1673 ungrab();
1674 flags|=FLAG_UPDATE;
1675 if(target && target->tryHandle(this,FXSEL(SEL_MIDDLEBUTTONRELEASE,message),ptr)) return 1;
1676 if(event->state&LEFTBUTTONMASK){
1677 setOp(ROTATING);
1678 grab();
1679 }
1680 else if(event->state&RIGHTBUTTONMASK){
1681 if(event->state&SHIFTMASK){
1682 setOp(GYRATING);
1683 }
1684 else if(event->state&CONTROLMASK){
1685 setOp(FOVING);
1686 }
1687 else{
1688 setOp(TRANSLATING);
1689 }
1690 grab();
1691 }
1692 else{
1693 setOp(HOVERING);
1694 }
1695 }
1696 return 1;
1697 }
1698
1699
1700 // Pressed right button
onRightBtnPress(FXObject *,FXSelector,void * ptr)1701 long FXGLViewer::onRightBtnPress(FXObject*,FXSelector,void* ptr){
1702 FXEvent* event=(FXEvent*)ptr;
1703 flags&=~FLAG_TIP;
1704 FXTRACE((100,"onRightBtnPress Mask=%08x\n",event->state));
1705 handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
1706 if(isEnabled()){
1707 grab();
1708 flags&=~FLAG_UPDATE;
1709 if(target && target->tryHandle(this,FXSEL(SEL_RIGHTBUTTONPRESS,message),ptr)) return 1;
1710 if(event->state&LEFTBUTTONMASK){
1711 if(event->state&SHIFTMASK){
1712 setOp(TRUCKING);
1713 }
1714 else{
1715 setOp(ZOOMING);
1716 }
1717 }
1718 else if(event->state&MIDDLEBUTTONMASK){
1719 if(event->state&SHIFTMASK){
1720 setOp(GYRATING);
1721 }
1722 else if(event->state&CONTROLMASK){
1723 setOp(FOVING);
1724 }
1725 else{
1726 setOp(TRANSLATING);
1727 }
1728 }
1729 else{
1730 if(event->state&SHIFTMASK){
1731 setOp(GYRATING);
1732 }
1733 else if(event->state&CONTROLMASK){
1734 setOp(FOVING);
1735 }
1736 else{
1737 setOp(POSTING);
1738 }
1739 }
1740 }
1741 return 1;
1742 }
1743
1744
1745 // Microsoft Visual C++: Disable compiler warnings for empty "if"
1746 // statements below in FXGLViewer::onRightBtnRelease()
1747 #ifdef _MSC_VER
1748 #pragma warning( disable : 4390 )
1749 #endif
1750
1751
1752 // Released right button
onRightBtnRelease(FXObject *,FXSelector,void * ptr)1753 long FXGLViewer::onRightBtnRelease(FXObject*,FXSelector,void* ptr){
1754 FXEvent* event=(FXEvent*)ptr;
1755 FXGLObject *hit;
1756 FXTRACE((100,"onRightBtnRelease Mask=%08x\n",event->state));
1757 if(isEnabled()){
1758 ungrab();
1759 flags|=FLAG_UPDATE;
1760 if(target && target->tryHandle(this,FXSEL(SEL_RIGHTBUTTONRELEASE,message),ptr)) return 1;
1761 if(event->state&LEFTBUTTONMASK){
1762 setOp(ROTATING);
1763 grab();
1764 }
1765 else if(event->state&MIDDLEBUTTONMASK){
1766 if(event->state&SHIFTMASK){
1767 setOp(TRUCKING);
1768 }
1769 else{
1770 setOp(ZOOMING);
1771 }
1772 grab();
1773 }
1774 else{
1775 if(mode==POSTING){
1776 setOp(HOVERING);
1777 hit=pick(event->click_x,event->click_y);
1778 if(hit && hit->handle(this,FXSEL(SEL_COMMAND,ID_QUERY_MENU),ptr))
1779 ;
1780 else if(target && target->tryHandle(this,FXSEL(SEL_COMMAND,ID_QUERY_MENU),ptr))
1781 ;
1782 }
1783 setOp(HOVERING);
1784 }
1785 }
1786 return 1;
1787 }
1788
1789
1790 // Mouse moved
onMotion(FXObject *,FXSelector,void * ptr)1791 long FXGLViewer::onMotion(FXObject*,FXSelector,void* ptr){
1792 FXEvent* event=(FXEvent*)ptr;
1793 FXint new_x,new_y,old_x,old_y;
1794 long changed=(flags&FLAG_TIP)!=0;
1795 FXdouble delta;
1796 FXfloat tmp;
1797 FXVec3f vec;
1798 FXQuatf q;
1799 flags&=~FLAG_TIP;
1800 if(isEnabled()){
1801 if(target && target->tryHandle(this,FXSEL(SEL_MOTION,message),ptr)) return 1;
1802 getApp()->removeTimeout(this,ID_TIPTIMER);
1803 switch(mode){
1804 case HOVERING: // Reset the timer each time we moved the cursor
1805 getApp()->addTimeout(this,ID_TIPTIMER,getApp()->getMenuPause());
1806 break;
1807 case PICKING: // Picking
1808 if(!event->moved){ // Keep picking mode for now
1809 break;
1810 }
1811 if(event->state&(SHIFTMASK|CONTROLMASK)){ // Lasso mode if modifier held down
1812 drawLasso(event->click_x,event->click_y,event->win_x,event->win_y);
1813 setOp(LASSOSELECT);
1814 break;
1815 }
1816 setOp(ROTATING); // Go into rotation mode
1817 case ROTATING: // Rotating camera around target
1818 q=turn(event->last_x,event->last_y,event->win_x,event->win_y) * getOrientation();
1819 setOrientation(q);
1820 changed=1;
1821 break;
1822 case POSTING: // Posting right-mouse menu; if moving more than delta, we go to translate mode
1823 if(!event->moved) break;
1824 setOp(TRANSLATING);
1825 case TRANSLATING: // Translating camera
1826 vec=worldVector(event->last_x,event->last_y,event->win_x,event->win_y);
1827 translate(-vec);
1828 changed=1;
1829 break;
1830 case ZOOMING: // Zooming camera
1831 delta=0.005*(event->win_y-event->last_y);
1832 setZoom(getZoom()*pow(2.0,delta));
1833 changed=1;
1834 break;
1835 case FOVING: // Change FOV
1836 setFieldOfView(getFieldOfView()+90.0*(event->win_y-event->last_y)/(double)wvt.h);
1837 changed=1;
1838 break;
1839 case DRAGGING: // Dragging a shape
1840 if(selection && selection->drag(this,event->last_x,event->last_y,event->win_x,event->win_y)){
1841 //// Perhaps callback here for the target to be notified of the new object position
1842 update();
1843 }
1844 changed=1;
1845 break;
1846 case TRUCKING: // Trucking camera forward or backward
1847 tmp=(FXfloat)(worldpx*(event->win_y-event->last_y));
1848 vec=normalize(getEyeVector());
1849 translate(tmp*vec);
1850 changed=1;
1851 break;
1852 case GYRATING: // Rotating camera around eye
1853 {
1854 FXMat4f mm;
1855 FXQuatf qq;
1856 qq=turn(event->win_x,event->win_y,event->last_x,event->last_y);
1857 mm.eye();
1858 mm.trans(0.0f,0.0f,(FXfloat)-distance); // FIXME This aint it yet...
1859 mm.rot(qq);
1860 mm.trans(0.0f,0.0f,(FXfloat)distance);
1861 center=center*mm;
1862 q=qq * getOrientation();
1863 setOrientation(q);
1864 update();
1865 changed=1;
1866 }
1867 break;
1868 case LASSOSELECT: // Dragging a lasso
1869 case LASSOZOOM:
1870 old_x=FXCLAMP(0,event->last_x,(width-1));
1871 old_y=FXCLAMP(0,event->last_y,(height-1));
1872 new_x=FXCLAMP(0,event->win_x,(width-1));
1873 new_y=FXCLAMP(0,event->win_y,(height-1));
1874 drawLasso(event->click_x,event->click_y,old_x,old_y);
1875 drawLasso(event->click_x,event->click_y,new_x,new_y);
1876 if(new_x>event->click_x){
1877 if(new_y>event->click_y)
1878 setDragCursor(getApp()->getDefaultCursor(DEF_CORNERSE_CURSOR));
1879 else
1880 setDragCursor(getApp()->getDefaultCursor(DEF_CORNERNE_CURSOR));
1881 }
1882 else{
1883 if(new_y>event->click_y)
1884 setDragCursor(getApp()->getDefaultCursor(DEF_CORNERSW_CURSOR));
1885 else
1886 setDragCursor(getApp()->getDefaultCursor(DEF_CORNERNW_CURSOR));
1887 }
1888 changed=1;
1889 break;
1890 }
1891 }
1892 return changed;
1893 }
1894
1895
1896 // Mouse wheel
onMouseWheel(FXObject *,FXSelector,void * ptr)1897 long FXGLViewer::onMouseWheel(FXObject*,FXSelector,void* ptr){
1898 FXEvent* event=(FXEvent*)ptr;
1899 if(isEnabled()){
1900 if(target && target->tryHandle(this,FXSEL(SEL_MOUSEWHEEL,message),ptr)) return 1;
1901 setZoom(getZoom()*pow(2.0,-0.1*event->code/120.0));
1902 return 1;
1903 }
1904 return 0;
1905 }
1906
1907
1908 // Handle keyboard press/release
onKeyPress(FXObject *,FXSelector,void * ptr)1909 long FXGLViewer::onKeyPress(FXObject*,FXSelector,void* ptr){
1910 FXEvent* event=(FXEvent*)ptr;
1911 flags&=~FLAG_TIP;
1912 if(isEnabled()){
1913 if(target && target->tryHandle(this,FXSEL(SEL_KEYPRESS,message),ptr)) return 1;
1914 switch(event->code){
1915 case KEY_Shift_L:
1916 case KEY_Shift_R:
1917
1918 // We do not switch modes unless something was going on already
1919 if(mode!=HOVERING){
1920 if((event->state&MIDDLEBUTTONMASK) || ((event->state&LEFTBUTTONMASK) && (event->state&RIGHTBUTTONMASK))){
1921 setOp(TRUCKING);
1922 }
1923 else if(event->state&RIGHTBUTTONMASK){
1924 setOp(GYRATING);
1925 }
1926 }
1927 return 1;
1928 case KEY_Control_L:
1929 case KEY_Control_R:
1930
1931 // We do not switch modes unless something was going on already
1932 if(mode!=HOVERING){
1933 if(event->state&RIGHTBUTTONMASK){
1934 setOp(FOVING);
1935 }
1936 }
1937 return 1;
1938 }
1939 }
1940 return 0;
1941 }
1942
1943
1944 // Key release
onKeyRelease(FXObject *,FXSelector,void * ptr)1945 long FXGLViewer::onKeyRelease(FXObject*,FXSelector,void* ptr){
1946 FXEvent* event=(FXEvent*)ptr;
1947 if(isEnabled()){
1948 if(target && target->tryHandle(this,FXSEL(SEL_KEYRELEASE,message),ptr)) return 1;
1949 switch(event->code){
1950 case KEY_Shift_L:
1951 case KEY_Shift_R:
1952
1953 // We do not switch modes unless something was going on already
1954 if(mode!=HOVERING){
1955 if((event->state&MIDDLEBUTTONMASK) || ((event->state&LEFTBUTTONMASK) && (event->state&RIGHTBUTTONMASK))){
1956 setOp(ZOOMING);
1957 }
1958 else if(event->state&RIGHTBUTTONMASK){
1959 setOp(TRANSLATING);
1960 }
1961 }
1962 return 1;
1963 case KEY_Control_L:
1964 case KEY_Control_R:
1965
1966 // We do not switch modes unless something was going on already
1967 if(mode!=HOVERING){
1968 if(event->state&RIGHTBUTTONMASK){
1969 setOp(TRANSLATING);
1970 }
1971 }
1972 return 1;
1973 }
1974 }
1975 return 0;
1976 }
1977
1978
1979 // The widget lost the grab for some reason
onUngrabbed(FXObject * sender,FXSelector sel,void * ptr)1980 long FXGLViewer::onUngrabbed(FXObject* sender,FXSelector sel,void* ptr){
1981 FXGLCanvas::onUngrabbed(sender,sel,ptr);
1982 flags&=~FLAG_PRESSED;
1983 flags&=~FLAG_CHANGED;
1984 flags|=FLAG_UPDATE;
1985 setOp(HOVERING);
1986 doesturbo=FALSE;
1987 return 1;
1988 }
1989
1990
1991 // We timed out, i.e. the user didn't move for a while
onTipTimer(FXObject *,FXSelector,void *)1992 long FXGLViewer::onTipTimer(FXObject*,FXSelector,void*){
1993 FXTRACE((250,"%s::onTipTimer %p\n",getClassName(),this));
1994 flags|=FLAG_TIP;
1995 return 1;
1996 }
1997
1998
1999 // We were asked about status text
onQueryHelp(FXObject * sender,FXSelector sel,void * ptr)2000 long FXGLViewer::onQueryHelp(FXObject* sender,FXSelector sel,void* ptr){
2001 if(FXWindow::onQueryHelp(sender,sel,ptr)) return 1;
2002 if((flags&FLAG_HELP) && !help.empty()){
2003 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&help);
2004 return 1;
2005 }
2006 return 0;
2007 }
2008
2009
2010 // We were asked about tip text
onQueryTip(FXObject * sender,FXSelector sel,void * ptr)2011 long FXGLViewer::onQueryTip(FXObject* sender,FXSelector sel,void* ptr){
2012 if(FXWindow::onQueryTip(sender,sel,ptr)) return 1;
2013 if(flags&FLAG_TIP){
2014 FXint x,y; FXuint state;
2015 getCursorPosition(x,y,state);
2016 FXGLObject *hit=pick(x,y);
2017 if(hit && hit->handle(sender,sel,ptr)) return 1;
2018 if(!tip.empty()){
2019 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&tip);
2020 return 1;
2021 }
2022 }
2023 return 0;
2024 }
2025
2026
2027 /***************************** Switch Projection *****************************/
2028
2029
2030 // Switch to perspective mode
onCmdPerspective(FXObject *,FXSelector,void *)2031 long FXGLViewer::onCmdPerspective(FXObject*,FXSelector,void*){
2032 setProjection(PERSPECTIVE);
2033 return 1;
2034 }
2035
2036
2037 // Update sender
onUpdPerspective(FXObject * sender,FXSelector,void *)2038 long FXGLViewer::onUpdPerspective(FXObject* sender,FXSelector,void*){
2039 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2040 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2041 sender->handle(this,(projection==PERSPECTIVE)?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2042 return 1;
2043 }
2044
2045
2046 // Switch to parallel mode
onCmdParallel(FXObject *,FXSelector,void *)2047 long FXGLViewer::onCmdParallel(FXObject*,FXSelector,void*){
2048 setProjection(PARALLEL);
2049 return 1;
2050 }
2051
2052
2053 // Update sender
onUpdParallel(FXObject * sender,FXSelector,void *)2054 long FXGLViewer::onUpdParallel(FXObject* sender,FXSelector,void*){
2055 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2056 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2057 sender->handle(this,(projection==PARALLEL)?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2058 return 1;
2059 }
2060
2061
2062 /***************************** Switch Viewpoints *****************************/
2063
2064 // View front
onCmdFront(FXObject *,FXSelector,void *)2065 long FXGLViewer::onCmdFront(FXObject*,FXSelector,void*){
2066 rotation=FXQuatf(0.0f,0.0f,0.0f,1.0f);
2067 updateTransform();
2068 update();
2069 return 1;
2070 }
2071
2072
2073 // Update sender
onUpdFront(FXObject * sender,FXSelector,void *)2074 long FXGLViewer::onUpdFront(FXObject* sender,FXSelector,void*){
2075 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2076 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2077 sender->handle(this,(EPS>fabs(rotation[0]) && EPS>fabs(rotation[1]) && EPS>fabs(rotation[2]) && EPS>fabs(rotation[3]-1.0)) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2078 return 1;
2079 }
2080
2081 // View back
onCmdBack(FXObject *,FXSelector,void *)2082 long FXGLViewer::onCmdBack(FXObject*,FXSelector,void*){
2083 rotation=FXQuatf(0.0f,-1.0f,0.0f,0.0f);
2084 updateTransform();
2085 update();
2086 return 1;
2087 }
2088
2089
2090 // Update sender
onUpdBack(FXObject * sender,FXSelector,void *)2091 long FXGLViewer::onUpdBack(FXObject* sender,FXSelector,void*){
2092 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2093 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2094 sender->handle(this,(EPS>fabs(rotation[0]) && EPS>fabs(rotation[1]+1.0) && EPS>fabs(rotation[2]) && EPS>fabs(rotation[3])) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2095 return 1;
2096 }
2097
2098 // View left
onCmdLeft(FXObject *,FXSelector,void *)2099 long FXGLViewer::onCmdLeft(FXObject*,FXSelector,void*){
2100 rotation=FXQuatf(0.0f,0.7071067811865f,0.0f,0.7071067811865f);
2101 updateTransform();
2102 update();
2103 return 1;
2104 }
2105
2106
2107 // Update sender
onUpdLeft(FXObject * sender,FXSelector,void *)2108 long FXGLViewer::onUpdLeft(FXObject* sender,FXSelector,void*){
2109 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2110 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2111 sender->handle(this,(EPS>fabs(rotation[0]) && EPS>fabs(rotation[1]-0.7071067811865) && EPS>fabs(rotation[2]) && EPS>fabs(rotation[3]-0.7071067811865)) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2112 return 1;
2113 }
2114
2115 // View right
onCmdRight(FXObject *,FXSelector,void *)2116 long FXGLViewer::onCmdRight(FXObject*,FXSelector,void*){
2117 rotation=FXQuatf(0.0f,-0.7071067811865f,0.0f,0.7071067811865f);
2118 updateTransform();
2119 update();
2120 return 1;
2121 }
2122
2123
2124 // Update sender
onUpdRight(FXObject * sender,FXSelector,void *)2125 long FXGLViewer::onUpdRight(FXObject* sender,FXSelector,void*){
2126 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2127 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2128 sender->handle(this,(EPS>fabs(rotation[0]) && EPS>fabs(rotation[1]+0.7071067811865) && EPS>fabs(rotation[2]) && EPS>fabs(rotation[3]-0.7071067811865)) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2129 return 1;
2130 }
2131
2132 // View top
onCmdTop(FXObject *,FXSelector,void *)2133 long FXGLViewer::onCmdTop(FXObject*,FXSelector,void*){
2134 rotation=FXQuatf(0.7071067811865f,0.0f,0.0f,0.7071067811865f);
2135 updateTransform();
2136 update();
2137 return 1;
2138 }
2139
2140
2141 // Update sender
onUpdTop(FXObject * sender,FXSelector,void *)2142 long FXGLViewer::onUpdTop(FXObject* sender,FXSelector,void*){
2143 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2144 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2145 sender->handle(this,(EPS>fabs(rotation[0]-0.7071067811865) && EPS>fabs(rotation[1]) && EPS>fabs(rotation[2]) && EPS>fabs(rotation[3]-0.7071067811865)) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2146 return 1;
2147 }
2148
2149 // View bottom
onCmdBottom(FXObject *,FXSelector,void *)2150 long FXGLViewer::onCmdBottom(FXObject*,FXSelector,void*){
2151 rotation=FXQuatf(-0.7071067811865f,0.0f,0.0f,0.7071067811865f);
2152 updateTransform();
2153 update();
2154 return 1;
2155 }
2156
2157
2158 // Update sender
onUpdBottom(FXObject * sender,FXSelector,void *)2159 long FXGLViewer::onUpdBottom(FXObject* sender,FXSelector,void*){
2160 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2161 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2162 sender->handle(this,(EPS>fabs(rotation[0]+0.7071067811865) && EPS>fabs(rotation[1]) && EPS>fabs(rotation[2]) && EPS>fabs(rotation[3]-0.7071067811865)) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2163 return 1;
2164 }
2165
2166
2167 // Reset view
onCmdResetView(FXObject *,FXSelector,void *)2168 long FXGLViewer::onCmdResetView(FXObject*,FXSelector,void*){
2169 FXRangef r(-1.0f,1.0f,-1.0f,1.0f,-1.0f,1.0f);
2170 rotation=FXQuatf(0.0f,0.0f,0.0f,1.0f);
2171 zoom=1.0;
2172 scale=FXVec3f(1.0f,1.0f,1.0f);
2173 if(scene) scene->bounds(r);
2174 setBounds(r);
2175 updateProjection();
2176 updateTransform();
2177 update();
2178 return 1;
2179 }
2180
2181
2182 // Fit view
onCmdFitView(FXObject *,FXSelector,void *)2183 long FXGLViewer::onCmdFitView(FXObject*,FXSelector,void*){
2184 FXRangef r(-1.0f,1.0f,-1.0f,1.0f,-1.0f,1.0f);
2185 if(scene) scene->bounds(r);
2186 setBounds(r);
2187 update();
2188 return 1;
2189 }
2190
2191
2192 // Update zoom
onUpdZoom(FXObject * sender,FXSelector,void *)2193 long FXGLViewer::onUpdZoom(FXObject* sender,FXSelector,void*){
2194 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETREALVALUE),(void*)&zoom);
2195 return 1;
2196 }
2197
2198
2199 // Change zoom
onCmdZoom(FXObject * sender,FXSelector sel,void *)2200 long FXGLViewer::onCmdZoom(FXObject* sender,FXSelector sel,void*){
2201 FXdouble z=zoom;
2202 sender->handle(this,FXSEL(SEL_COMMAND,ID_GETREALVALUE),(void*)&z);
2203 doesturbo=(FXSELTYPE(sel)==SEL_CHANGED)?turbomode:FALSE;
2204 setZoom(z);
2205 return 1;
2206 }
2207
2208
2209 // Update field of view
onUpdFov(FXObject * sender,FXSelector,void *)2210 long FXGLViewer::onUpdFov(FXObject* sender,FXSelector,void*){
2211 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETREALVALUE),(void*)&fov);
2212 return 1;
2213 }
2214
2215
2216 // Change field of view
onCmdFov(FXObject * sender,FXSelector sel,void *)2217 long FXGLViewer::onCmdFov(FXObject* sender,FXSelector sel,void*){
2218 FXdouble f=fov;
2219 sender->handle(this,FXSEL(SEL_COMMAND,ID_GETREALVALUE),(void*)&f);
2220 doesturbo=(FXSELTYPE(sel)==SEL_CHANGED)?turbomode:FALSE;
2221 setFieldOfView(f);
2222 return 1;
2223 }
2224
2225
2226 // Scale model
onCmdXYZScale(FXObject * sender,FXSelector sel,void *)2227 long FXGLViewer::onCmdXYZScale(FXObject* sender,FXSelector sel,void*){
2228 FXVec3f s=scale;
2229 FXdouble value;
2230 sender->handle(this,FXSEL(SEL_COMMAND,ID_GETREALVALUE),&value);
2231 s[FXSELID(sel)-ID_SCALE_X]=(FXfloat)value;
2232 doesturbo=(FXSELTYPE(sel)==SEL_CHANGED)?turbomode:FALSE;
2233 setScale(s);
2234 return 1;
2235 }
2236
2237
2238 // Update scale value
onUpdXYZScale(FXObject * sender,FXSelector sel,void *)2239 long FXGLViewer::onUpdXYZScale(FXObject* sender,FXSelector sel,void*){
2240 FXdouble value=scale[FXSELID(sel)-ID_SCALE_X];
2241 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETREALVALUE),(void*)&value);
2242 return 1;
2243 }
2244
2245
2246 // Rotate camera about model by means of dials
onCmdXYZDial(FXObject *,FXSelector sel,void * ptr)2247 long FXGLViewer::onCmdXYZDial(FXObject*,FXSelector sel,void* ptr){
2248 const FXVec3f xaxis(1.0f,0.0f,0.0f);
2249 const FXVec3f yaxis(0.0f,1.0f,0.0f);
2250 const FXVec3f zaxis(0.0f,0.0f,1.0f);
2251 FXint dialnew=(FXint)(FXival)ptr;
2252 FXfloat ang;
2253 FXQuatf q;
2254 if(FXSELTYPE(sel)==SEL_CHANGED){
2255 doesturbo=turbomode;
2256 FXASSERT(ID_DIAL_X<=FXSELID(sel) && FXSELID(sel)<=ID_DIAL_Z);
2257 switch(FXSELID(sel)){
2258 case ID_DIAL_X:
2259 ang=(FXfloat)(DTOR*(dialnew-dial[0]));
2260 q.setAxisAngle(xaxis,-ang);
2261 dial[0]=dialnew;
2262 break;
2263 case ID_DIAL_Y:
2264 ang=(FXfloat)(DTOR*(dialnew-dial[1]));
2265 q.setAxisAngle(yaxis, ang);
2266 dial[1]=dialnew;
2267 break;
2268 case ID_DIAL_Z:
2269 ang=(FXfloat)(DTOR*(dialnew-dial[2]));
2270 q.setAxisAngle(zaxis, ang);
2271 dial[2]=dialnew;
2272 break;
2273 }
2274 setOrientation(q*getOrientation());
2275 }
2276 else if(doesturbo){
2277 doesturbo=FALSE;
2278 update();
2279 }
2280 return 1;
2281 }
2282
2283
2284 // Update dial value
onUpdXYZDial(FXObject * sender,FXSelector sel,void *)2285 long FXGLViewer::onUpdXYZDial(FXObject* sender,FXSelector sel,void*){
2286 FXASSERT(ID_DIAL_X<=FXSELID(sel) && FXSELID(sel)<=ID_DIAL_Z);
2287 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETINTVALUE),(void*)&dial[FXSELID(sel)-ID_DIAL_X]);
2288 return 1;
2289 }
2290
2291
2292 // Update roll pitch yaw
onCmdRollPitchYaw(FXObject * sender,FXSelector sel,void *)2293 long FXGLViewer::onCmdRollPitchYaw(FXObject* sender,FXSelector sel,void*){
2294 FXASSERT(ID_ROLL<=FXSELID(sel) && FXSELID(sel)<=ID_YAW);
2295 FXfloat rpy[3];
2296 FXdouble ang;
2297 rotation.getRollPitchYaw(rpy[0],rpy[1],rpy[2]);
2298 sender->handle(this,FXSEL(SEL_COMMAND,ID_GETREALVALUE),(void*)&ang);
2299 rpy[FXSELID(sel)-ID_ROLL]=(FXfloat)(DTOR*ang);
2300 doesturbo=(FXSELTYPE(sel)==SEL_CHANGED)?turbomode:FALSE;
2301 setOrientation(FXQuatf(rpy[0],rpy[1],rpy[2]));
2302 update();
2303 return 1;
2304 }
2305
2306
2307 // Update roll pitch yaw
onUpdRollPitchYaw(FXObject * sender,FXSelector sel,void *)2308 long FXGLViewer::onUpdRollPitchYaw(FXObject* sender,FXSelector sel,void*){
2309 FXASSERT(ID_ROLL<=FXSELID(sel) && FXSELID(sel)<=ID_YAW);
2310 FXfloat rpy[3];
2311 rotation.getRollPitchYaw(rpy[0],rpy[1],rpy[2]);
2312 FXdouble ang=RTOD*rpy[FXSELID(sel)-ID_ROLL];
2313 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETREALVALUE),(void*)&ang);
2314 return 1;
2315 }
2316
2317
2318 /****************************** Printing Support *****************************/
2319
2320
2321 // Read back pixels
2322 // Derived from code contributed by <sancelot@crosswinds.net>
readPixels(FXColor * & buffer,FXint x,FXint y,FXint w,FXint h)2323 FXbool FXGLViewer::readPixels(FXColor*& buffer,FXint x,FXint y,FXint w,FXint h){
2324 #ifdef HAVE_GL_H
2325 if(1<=w && 1<=h){
2326 GLint swapbytes,lsbfirst,rowlength,skiprows,skippixels,alignment,oldbuf;
2327 register FXColor *p,*q,*pp,*qq,t;
2328
2329 // Try allocate buffer
2330 if(FXMALLOC(&buffer,FXColor,w*h)){
2331
2332 // Make context current
2333 makeCurrent();
2334
2335 // Save old pixel formats
2336 glGetIntegerv(GL_PACK_SWAP_BYTES,&swapbytes);
2337 glGetIntegerv(GL_PACK_LSB_FIRST,&lsbfirst);
2338 glGetIntegerv(GL_PACK_ROW_LENGTH,&rowlength);
2339 glGetIntegerv(GL_PACK_SKIP_ROWS,&skiprows);
2340 glGetIntegerv(GL_PACK_SKIP_PIXELS,&skippixels);
2341 glGetIntegerv(GL_PACK_ALIGNMENT,&alignment);
2342 glGetIntegerv(GL_READ_BUFFER,&oldbuf);
2343
2344 // Set pixel readback formats
2345 glPixelStorei(GL_PACK_SWAP_BYTES,GL_FALSE);
2346 glPixelStorei(GL_PACK_LSB_FIRST,GL_FALSE);
2347 glPixelStorei(GL_PACK_ROW_LENGTH,0);
2348 glPixelStorei(GL_PACK_SKIP_ROWS,0);
2349 glPixelStorei(GL_PACK_SKIP_PIXELS,0);
2350 glPixelStorei(GL_PACK_ALIGNMENT,1);
2351
2352 // Read from the right buffer
2353 glReadBuffer((GLenum)GL_FRONT);
2354
2355 // Read the pixels
2356 glReadPixels(x,y,w,h,GL_RGBA,GL_UNSIGNED_BYTE,(GLvoid*)buffer);
2357
2358 // Flip image upside down
2359 pp=buffer;
2360 qq=buffer+(h-1)*w;
2361 do{
2362 p=pp; pp+=w;
2363 q=qq; qq-=w;
2364 do{
2365 FXSWAP(*p,*q,t);
2366 p++;
2367 q++;
2368 }
2369 while(p<pp);
2370 }
2371 while(pp<qq);
2372
2373 // Restore old formats
2374 glPixelStorei(GL_PACK_SWAP_BYTES,swapbytes);
2375 glPixelStorei(GL_PACK_LSB_FIRST,lsbfirst);
2376 glPixelStorei(GL_PACK_ROW_LENGTH,rowlength);
2377 glPixelStorei(GL_PACK_SKIP_ROWS,skiprows);
2378 glPixelStorei(GL_PACK_SKIP_PIXELS,skippixels);
2379 glPixelStorei(GL_PACK_ALIGNMENT,alignment);
2380 glReadBuffer((GLenum)oldbuf);
2381
2382 // Make context non-current
2383 makeNonCurrent();
2384 return TRUE;
2385 }
2386 }
2387 #endif
2388 return FALSE;
2389 }
2390
2391
2392 // Print the window by grabbing pixels
onCmdPrintImage(FXObject *,FXSelector,void *)2393 long FXGLViewer::onCmdPrintImage(FXObject*,FXSelector,void*){
2394 FXColor *buffer;
2395
2396 // First, ensure window is fully painted
2397 repaint();
2398 getApp()->flush(TRUE);
2399
2400 // Then try grab the pixels
2401 if(readPixels(buffer,0,0,width,height)){
2402 // FXFileStream outfile;
2403 // if(outfile.open("testje.bmp",FXStreamSave)){
2404 // fxsaveBMP(outfile,buffer,width,height);
2405 // outfile.close();
2406 // }
2407
2408 // Open print dialog
2409 FXPrintDialog dlg(this,tr("Print Scene"));
2410
2411 // Run dialog
2412 if(dlg.execute()){
2413 FXPrinter printer;
2414
2415 // Get the printer
2416 dlg.getPrinter(printer);
2417
2418 // Printer device context
2419 FXDCPrint pdc(getApp());
2420
2421 // Try open printer
2422 if(!pdc.beginPrint(printer)){
2423 FXMessageBox::error(this,MBOX_OK,tr("Printer Error"),tr("Unable to print."));
2424 return 1;
2425 }
2426
2427 // Page header
2428 pdc.beginPage(1);
2429
2430 // This is very ad-hoc; please don't look
2431 pdc.outf("/picstr %d string def\n",width*3);
2432 pdc.outf("%d %d translate\n",50,50);
2433 pdc.outf("%d %d scale\n",width,height);
2434 pdc.outf("%d %d %d\n",width,height,8);
2435 pdc.outf("[%d 0 0 -%d 0 %d]\n",width,height,height);
2436 pdc.outf("{currentfile picstr readhexstring pop}\n");
2437 pdc.outf("false %d\n",3);
2438 pdc.outf("colorimage\n");
2439 for(int i=0; i<width*height; i++){
2440 pdc.outhex(FXREDVAL(buffer[i]));
2441 pdc.outhex(FXGREENVAL(buffer[i]));
2442 pdc.outhex(FXBLUEVAL(buffer[i]));
2443 }
2444 pdc.outf("\n");
2445
2446 // Page trailer
2447 pdc.endPage();
2448 pdc.endPrint();
2449 }
2450
2451 // Free the pixels
2452 FXFREE(&buffer);
2453 }
2454 return 1;
2455 }
2456
2457
2458 // Render
renderFeedback(FXfloat * buffer,FXint x,FXint y,FXint w,FXint h,FXint maxbuffer)2459 FXint FXGLViewer::renderFeedback(FXfloat *buffer,FXint x,FXint y,FXint w,FXint h,FXint maxbuffer){
2460 #ifdef HAVE_GL_H
2461 FXint used;
2462 makeCurrent();
2463 glFeedbackBuffer(maxbuffer,GL_3D_COLOR,buffer);
2464 glRenderMode(GL_FEEDBACK);
2465 drawWorld(wvt);
2466 used=glRenderMode(GL_RENDER);
2467 makeNonCurrent();
2468 return used;
2469 #else
2470 return -1;
2471 #endif
2472 }
2473
2474
2475 // Read feedback buffer
readFeedback(FXfloat * & buffer,FXint & used,FXint & size,FXint x,FXint y,FXint w,FXint h)2476 FXbool FXGLViewer::readFeedback(FXfloat*& buffer,FXint& used,FXint& size,FXint x,FXint y,FXint w,FXint h){
2477 FXbool ok=FALSE;
2478 buffer=NULL;
2479 used=0;
2480 size=10000;
2481 while(1){
2482
2483 // Allocate buffer
2484 FXMALLOC(&buffer,FXfloat,size);
2485
2486 // It got too big, give up
2487 if(!buffer) break;
2488
2489 // Try to render scene into it
2490 used=renderFeedback(buffer,x,y,w,h,size);
2491
2492 // No errors, got our stuff
2493 if(0<used){
2494 ok=TRUE;
2495 break;
2496 }
2497
2498 // It didn't fit, lets double the buffer and try again
2499 FXFREE(&buffer);
2500 size*=2;
2501 continue;
2502 }
2503 return ok;
2504 }
2505
2506
2507 // Draw feedback buffer into dc
drawFeedback(FXDCPrint & pdc,const FXfloat * buffer,FXint used)2508 void FXGLViewer::drawFeedback(FXDCPrint& pdc,const FXfloat* buffer,FXint used){
2509 #ifdef HAVE_GL_H
2510 FXint nvertices,smooth,token,i,p;
2511
2512 // Draw background
2513 pdc.outf("%g %g %g C\n",background[0][0],background[0][1],background[0][2]);
2514 pdc.outf("newpath\n");
2515 pdc.outf("%g %g moveto\n",0.0,0.0);
2516 pdc.outf("%g %g lineto\n",0.0,(double)height);
2517 pdc.outf("%g %g lineto\n",(double)width,(double)height);
2518 pdc.outf("%g %g lineto\n",(double)width,0.0);
2519 pdc.outf("closepath fill\n");
2520
2521 pdc.outf("1 setlinewidth\n");
2522
2523 // Crank out primitives
2524 p=0;
2525 while(p<used){
2526 token=(FXint)buffer[p++];
2527 switch(token){
2528
2529 // Point primitive
2530 case GL_POINT_TOKEN:
2531 pdc.outf("%g %g %g %g %g P\n",buffer[p+0],buffer[p+1],buffer[p+3],buffer[p+4],buffer[p+5]);
2532 p+=7; // Each vertex element in the feedback buffer is 7 floats
2533 break;
2534
2535 // Line primitive
2536 case GL_LINE_RESET_TOKEN:
2537 case GL_LINE_TOKEN:
2538 if(fabs(buffer[p+3]-buffer[p+7+3])<1E-4 || fabs(buffer[p+4]-buffer[p+7+4])<1E-4 || fabs(buffer[p+5]-buffer[p+7+5])<1E-4){
2539 pdc.outf("%g %g %g %g %g %g %g %g %g %g SL\n",buffer[p+0],buffer[p+1],buffer[p+3],buffer[p+4],buffer[p+5], buffer[p+7+0],buffer[p+7+1],buffer[p+7+3],buffer[p+7+4],buffer[p+7+5]);
2540 }
2541 else{
2542 pdc.outf("%g %g %g %g %g %g %g L\n",buffer[p+0],buffer[p+1],buffer[p+7+0],buffer[p+7+1],buffer[p+3],buffer[p+4],buffer[p+5]);
2543 }
2544 p+=14; // Each vertex element in the feedback buffer is 7 GLfloats
2545 break;
2546
2547 // Polygon primitive
2548 case GL_POLYGON_TOKEN:
2549 nvertices = (FXint)buffer[p++];
2550 if(nvertices==3){ // We assume polybusting has taken place already!
2551 smooth=0;
2552 for(i=1; i<nvertices; i++){
2553 if(fabs(buffer[p+3]-buffer[p+i*7+3])<1E-4 || fabs(buffer[p+4]-buffer[p+i*7+4])<1E-4 || fabs(buffer[p+5]-buffer[p+i*7+5])<1E-4){ smooth=1; break; }
2554 }
2555 if(smooth){
2556 pdc.outf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n",buffer[p+0],buffer[p+1],buffer[p+3],buffer[p+4],buffer[p+5], buffer[p+7+0],buffer[p+7+1],buffer[p+7+3],buffer[p+7+4],buffer[p+7+5], buffer[p+14+0],buffer[p+14+1],buffer[p+14+3],buffer[p+14+4],buffer[p+14+5]);
2557 }
2558 else{
2559 pdc.outf("%g %g %g %g %g %g %g %g %g T\n",buffer[p+0],buffer[p+1], buffer[p+7+0],buffer[p+7+1], buffer[p+14+0],buffer[p+14+1], buffer[p+3],buffer[p+4],buffer[p+5]);
2560 }
2561 }
2562 p+=nvertices*7; // Each vertex element in the feedback buffer is 7 GLfloats
2563 break;
2564
2565 // Skip these, don't deal with it here
2566 case GL_BITMAP_TOKEN:
2567 case GL_DRAW_PIXEL_TOKEN:
2568 case GL_COPY_PIXEL_TOKEN:
2569 p+=7;
2570 break;
2571
2572 // Skip passthrough tokens
2573 case GL_PASS_THROUGH_TOKEN:
2574 p++;
2575 break;
2576
2577 // Bad token, this is the end
2578 default:
2579 return;
2580 }
2581 }
2582 #endif
2583 }
2584
2585
2586 // Print the window by means of feedback buffer
onCmdPrintVector(FXObject *,FXSelector,void *)2587 long FXGLViewer::onCmdPrintVector(FXObject*,FXSelector,void*){
2588 FXPrintDialog dlg(this,tr("Print Scene"));
2589 FXPrinter printer;
2590 FXfloat *buffer;
2591 FXint used,size;
2592
2593 // Run dialog
2594 if(dlg.execute()){
2595 dlg.getPrinter(printer);
2596 FXDCPrint pdc(getApp());
2597 if(!pdc.beginPrint(printer)){
2598 FXMessageBox::error(this,MBOX_OK,tr("Printer Error"),tr("Unable to print."));
2599 return 1;
2600 }
2601
2602 // Repaint now
2603 repaint();
2604
2605 // Flush commands
2606 getApp()->flush(TRUE);
2607
2608 // Page header
2609 pdc.beginPage(1);
2610
2611 // Read feedback
2612 if(readFeedback(buffer,used,size,0,0,width,height)){
2613 if(zsortfunc) (*zsortfunc)(buffer,used,size); // FIXME:- may throw exception
2614 drawFeedback(pdc,buffer,used);
2615 }
2616
2617 // Page trailer
2618 pdc.endPage();
2619 pdc.endPrint();
2620 }
2621 return 1;
2622 }
2623
2624
2625 // Zoom into lasso rectangle
onCmdLassoZoom(FXObject *,FXSelector,void *)2626 long FXGLViewer::onCmdLassoZoom(FXObject*,FXSelector,void*){
2627 setOp(DO_LASSOZOOM);
2628 return 1;
2629 }
2630
2631 // Select objects in lasso rectangle
onCmdLassoSelect(FXObject *,FXSelector,void *)2632 long FXGLViewer::onCmdLassoSelect(FXObject*,FXSelector,void*){
2633 setOp(DO_LASSOSELECT);
2634 return 1;
2635 }
2636
2637 /***************************** Selection Support *****************************/
2638
2639 // We now really do have the selection
onClipboardGained(FXObject * sender,FXSelector sel,void * ptr)2640 long FXGLViewer::onClipboardGained(FXObject* sender,FXSelector sel,void* ptr){
2641 FXGLCanvas::onClipboardGained(sender,sel,ptr);
2642 return 1;
2643 }
2644
2645
2646 // We lost the selection somehow
onClipboardLost(FXObject * sender,FXSelector sel,void * ptr)2647 long FXGLViewer::onClipboardLost(FXObject* sender,FXSelector sel,void* ptr){
2648 FXGLCanvas::onClipboardLost(sender,sel,ptr);
2649 return 1;
2650 }
2651
2652
2653 // Somebody wants our selection
onClipboardRequest(FXObject * sender,FXSelector sel,void * ptr)2654 long FXGLViewer::onClipboardRequest(FXObject* sender,FXSelector sel,void* ptr){
2655 FXEvent *event=(FXEvent*)ptr;
2656 // FXuchar *data; FXuint len;
2657
2658 // Try handling it in base class first
2659 if(FXGLCanvas::onClipboardRequest(sender,sel,ptr)) return 1;
2660
2661 // Requested data from clipboard
2662 if(event->target==objectType){
2663 FXTRACE((100,"requested objectType\n"));
2664 // FXMemoryStream stream;
2665 // stream.open(NULL,0,FXStreamSave);
2666 // stream.takeBuffer(data,len);
2667 // stream.close();
2668 // setDNDData(FROM_CLIPBOARD,objectType,data,len);
2669 return 1;
2670 }
2671
2672 return 0;
2673 }
2674
2675 // Cut selected object
onCmdCutSel(FXObject *,FXSelector,void *)2676 long FXGLViewer::onCmdCutSel(FXObject*,FXSelector,void*){
2677 // Serialize object into temp buffer
2678 // Delete object, tell target it was deleted
2679 //fxwarning("%s::onCmdCutSel: unimplemented.\n",getClassName());
2680 return 1;
2681 }
2682
2683
2684 // Copy selected object
onCmdCopySel(FXObject *,FXSelector,void *)2685 long FXGLViewer::onCmdCopySel(FXObject*,FXSelector,void*){
2686 // Serialize object into buffer
2687 //fxwarning("%s::onCmdCopySel: unimplemented.\n",getClassName());
2688 return 1;
2689 }
2690
2691
2692 // Paste object
onCmdPasteSel(FXObject *,FXSelector,void *)2693 long FXGLViewer::onCmdPasteSel(FXObject*,FXSelector,void*){
2694 // Ask clipboard for object data [What type?]
2695 // Deserialize data [type?]
2696 // Tell target about the data?
2697 //fxwarning("%s::onCmdPasteSel: unimplemented.\n",getClassName());
2698 return 1;
2699 }
2700
2701
2702 // Delete selected object
onCmdDeleteSel(FXObject *,FXSelector,void *)2703 long FXGLViewer::onCmdDeleteSel(FXObject*,FXSelector,void*){
2704 FXGLObject *obj[2];
2705 obj[0]=selection;
2706 obj[1]=NULL;
2707 if(obj[0] && obj[0]->canDelete()){
2708 handle(this,FXSEL(SEL_CHANGED,0),NULL);
2709 handle(this,FXSEL(SEL_DELETED,0),(void*)obj);
2710 //delete obj[0];
2711 }
2712 else{
2713 getApp()->beep();
2714 }
2715 return 1;
2716 }
2717
2718
2719 // Update delete object
onUpdDeleteSel(FXObject * sender,FXSelector,void *)2720 long FXGLViewer::onUpdDeleteSel(FXObject* sender,FXSelector,void*){
2721 if(selection && selection->canDelete()){
2722 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2723 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2724 return 1;
2725 }
2726 return 0;
2727 }
2728
2729
2730 // Update for current object
onUpdCurrent(FXObject * sender,FXSelector,void *)2731 long FXGLViewer::onUpdCurrent(FXObject* sender,FXSelector,void*){
2732 if(selection){
2733 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2734 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2735 return 1;
2736 }
2737 return 0;
2738 }
2739
2740
2741 // Set background color
onCmdBackColor(FXObject *,FXSelector sel,void * ptr)2742 long FXGLViewer::onCmdBackColor(FXObject*,FXSelector sel,void* ptr){
2743 FXColor color=(FXColor)(FXuval)ptr;
2744 background[0]=background[1]=color;
2745 if(FXSELTYPE(sel)==SEL_COMMAND || !turbomode){
2746 update();
2747 }
2748 return 1;
2749 }
2750
2751
2752 // Update background color
onUpdBackColor(FXObject * sender,FXSelector,void *)2753 long FXGLViewer::onUpdBackColor(FXObject* sender,FXSelector,void*){
2754 FXColor clr=background[0];
2755 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETVALUE),(void*)(FXuval)clr);
2756 return 1;
2757 }
2758
2759
2760 // Set gradient background color
onCmdGradientBackColor(FXObject *,FXSelector sel,void * ptr)2761 long FXGLViewer::onCmdGradientBackColor(FXObject*,FXSelector sel,void* ptr){
2762 FXColor color=(FXColor)(FXuval)ptr;
2763 background[FXSELID(sel)-ID_TOP_COLOR]=color;
2764 if(FXSELTYPE(sel)==SEL_COMMAND || !turbomode){
2765 update();
2766 }
2767 return 1;
2768 }
2769
2770
2771 // Update gradient background color
onUpdGradientBackColor(FXObject * sender,FXSelector sel,void *)2772 long FXGLViewer::onUpdGradientBackColor(FXObject* sender,FXSelector sel,void*){
2773 FXColor clr=background[FXSELID(sel)-ID_TOP_COLOR];
2774 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETVALUE),(void*)(FXuval)clr);
2775 return 1;
2776 }
2777
2778
2779 // Set ambient light color
onCmdAmbientColor(FXObject *,FXSelector sel,void * ptr)2780 long FXGLViewer::onCmdAmbientColor(FXObject*,FXSelector sel,void* ptr){
2781 FXColor color=(FXColor)(FXuval)ptr;
2782 ambient=color;
2783 if(FXSELTYPE(sel)==SEL_COMMAND || !turbomode){
2784 update();
2785 }
2786 return 1;
2787 }
2788
2789
2790 // Update ambient light color
onUpdAmbientColor(FXObject * sender,FXSelector,void *)2791 long FXGLViewer::onUpdAmbientColor(FXObject* sender,FXSelector,void*){
2792 FXColor clr=ambient;
2793 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETVALUE),(void*)(FXuval)clr);
2794 return 1;
2795 }
2796
2797
2798 // Set ambient light color
onCmdLightAmbient(FXObject *,FXSelector sel,void * ptr)2799 long FXGLViewer::onCmdLightAmbient(FXObject*,FXSelector sel,void* ptr){
2800 FXColor color=(FXColor)(FXuval)ptr;
2801 light.ambient=color;
2802 if(FXSELTYPE(sel)==SEL_COMMAND || !turbomode){
2803 update();
2804 }
2805 return 1;
2806 }
2807
2808
2809 // Update ambient light color
onUpdLightAmbient(FXObject * sender,FXSelector,void *)2810 long FXGLViewer::onUpdLightAmbient(FXObject* sender,FXSelector,void*){
2811 FXColor clr=light.ambient;
2812 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETVALUE),(void*)(FXuval)clr);
2813 return 1;
2814 }
2815
2816
2817 // Set diffuse light color
onCmdLightDiffuse(FXObject *,FXSelector sel,void * ptr)2818 long FXGLViewer::onCmdLightDiffuse(FXObject*,FXSelector sel,void* ptr){
2819 FXColor color=(FXColor)(FXuval)ptr;
2820 light.diffuse=color;
2821 if(FXSELTYPE(sel)==SEL_COMMAND || !turbomode){
2822 update();
2823 }
2824 return 1;
2825 }
2826
2827
2828 // Update diffuse light color
onUpdLightDiffuse(FXObject * sender,FXSelector,void *)2829 long FXGLViewer::onUpdLightDiffuse(FXObject* sender,FXSelector,void*){
2830 FXColor clr=light.diffuse;
2831 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETVALUE),(void*)(FXuval)clr);
2832 return 1;
2833 }
2834
2835
2836 // Set specular light color
onCmdLightSpecular(FXObject *,FXSelector sel,void * ptr)2837 long FXGLViewer::onCmdLightSpecular(FXObject*,FXSelector sel,void* ptr){
2838 FXColor color=(FXColor)(FXuval)ptr;
2839 light.specular=color;
2840 if(FXSELTYPE(sel)==SEL_COMMAND || !turbomode){
2841 update();
2842 }
2843 return 1;
2844 }
2845
2846
2847 // Update specular light color
onUpdLightSpecular(FXObject * sender,FXSelector,void *)2848 long FXGLViewer::onUpdLightSpecular(FXObject* sender,FXSelector,void*){
2849 FXColor clr=light.specular;
2850 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETVALUE),(void*)(FXuval)clr);
2851 return 1;
2852 }
2853
2854
2855 // Toggle Turbo Mode
onCmdTurbo(FXObject *,FXSelector,void *)2856 long FXGLViewer::onCmdTurbo(FXObject*,FXSelector,void*){
2857 setTurboMode(!getTurboMode());
2858 return 1;
2859 }
2860
2861
2862 // Update Turbo Mode
onUpdTurbo(FXObject * sender,FXSelector,void *)2863 long FXGLViewer::onUpdTurbo(FXObject* sender,FXSelector,void*){
2864 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2865 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2866 sender->handle(this,getTurboMode() ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2867 return 1;
2868 }
2869
2870
2871 // Toggle lighting
onCmdLighting(FXObject *,FXSelector,void *)2872 long FXGLViewer::onCmdLighting(FXObject*,FXSelector,void*){
2873 options^=VIEWER_LIGHTING;
2874 update();
2875 return 1;
2876 }
2877
2878
2879 // Update lighting
onUpdLighting(FXObject * sender,FXSelector,void *)2880 long FXGLViewer::onUpdLighting(FXObject* sender,FXSelector,void*){
2881 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2882 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2883 sender->handle(this,(options&VIEWER_LIGHTING) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2884 return 1;
2885 }
2886
2887
2888 // Toggle fog
onCmdFog(FXObject *,FXSelector,void *)2889 long FXGLViewer::onCmdFog(FXObject*,FXSelector,void*){
2890 options^=VIEWER_FOG;
2891 update();
2892 return 1;
2893 }
2894
2895
2896 // Update fog
onUpdFog(FXObject * sender,FXSelector,void *)2897 long FXGLViewer::onUpdFog(FXObject* sender,FXSelector,void*){
2898 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2899 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2900 sender->handle(this,(options&VIEWER_FOG) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2901 return 1;
2902 }
2903
2904
2905 // Toggle dithering
onCmdDither(FXObject *,FXSelector,void *)2906 long FXGLViewer::onCmdDither(FXObject*,FXSelector,void*){
2907 options^=VIEWER_DITHER;
2908 update();
2909 return 1;
2910 }
2911
2912
2913 // Update dithering
onUpdDither(FXObject * sender,FXSelector,void *)2914 long FXGLViewer::onUpdDither(FXObject* sender,FXSelector,void*){
2915 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
2916 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
2917 sender->handle(this,(options&VIEWER_DITHER) ? FXSEL(SEL_COMMAND,ID_CHECK) : FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
2918 return 1;
2919 }
2920
2921
2922 /******************************* Drag and Drop *******************************/
2923
2924
2925 // Handle drag-and-drop enter
onDNDEnter(FXObject * sender,FXSelector sel,void * ptr)2926 long FXGLViewer::onDNDEnter(FXObject* sender,FXSelector sel,void* ptr){
2927 if(FXGLCanvas::onDNDEnter(sender,sel,ptr)) return 1;
2928 dropped=NULL;
2929 return 1;
2930 }
2931
2932 // Handle drag-and-drop leave
onDNDLeave(FXObject * sender,FXSelector sel,void * ptr)2933 long FXGLViewer::onDNDLeave(FXObject* sender,FXSelector sel,void* ptr){
2934 if(FXGLCanvas::onDNDLeave(sender,sel,ptr)) return 1;
2935 dropped=NULL;
2936 return 1;
2937 }
2938
2939
2940 // Handle drag-and-drop motion
onDNDMotion(FXObject * sender,FXSelector sel,void * ptr)2941 long FXGLViewer::onDNDMotion(FXObject* sender,FXSelector sel,void* ptr){
2942 FXEvent* event=(FXEvent*)ptr;
2943
2944 // Handled elsewhere
2945 if(FXGLCanvas::onDNDMotion(sender,sel,ptr)) return 1;
2946
2947 // Dropped on some object
2948 if((dropped=pick(event->win_x,event->win_y))!=NULL){
2949
2950 // Object agrees with drop type
2951 if(dropped->handle(this,sel,ptr)){
2952 acceptDrop(DRAG_COPY);
2953 return 1;
2954 }
2955
2956 // Forget about the whole thing
2957 dropped=NULL;
2958 return 0;
2959 }
2960
2961 // Dropped in viewer background; hope its a color
2962 if(offeredDNDType(FROM_DRAGNDROP,colorType)){
2963 acceptDrop(DRAG_COPY);
2964 return 1;
2965 }
2966
2967 // Won't accept drop, dont know what it is
2968 return 0;
2969 }
2970
2971
2972 // Handle drag-and-drop drop
onDNDDrop(FXObject * sender,FXSelector sel,void * ptr)2973 long FXGLViewer::onDNDDrop(FXObject* sender,FXSelector sel,void* ptr){
2974 FXushort *clr; FXuint len;
2975
2976 // Try base class first
2977 if(FXGLCanvas::onDNDDrop(sender,sel,ptr)) return 1;
2978
2979 // Dropped on object?
2980 if(dropped){
2981
2982 // Object handled drop; so probably want to repaint
2983 if(dropped->handle(this,sel,ptr)){
2984 update();
2985 return 1;
2986 }
2987
2988 // We're done
2989 return 0;
2990 }
2991
2992 // Dropped on viewer
2993 if(getDNDData(FROM_DRAGNDROP,FXGLViewer::colorType,(FXuchar*&)clr,len)){
2994 setBackgroundColor(FXVec4f(clr[0]/65535.0f,clr[1]/65535.0f,clr[2]/65535.0f,1.0f));
2995 FXFREE(&clr);
2996 update();
2997 return 1;
2998 }
2999 return 0;
3000 }
3001
3002
3003 // Change projection
setProjection(FXuint proj)3004 void FXGLViewer::setProjection(FXuint proj){
3005 projection=proj;
3006 updateProjection();
3007 update();
3008 }
3009
3010
3011 // Set background
setBackgroundColor(const FXVec4f & clr,FXbool bottom)3012 void FXGLViewer::setBackgroundColor(const FXVec4f& clr,FXbool bottom){
3013 if(bottom==MAYBE){
3014 background[0]=background[1]=clr;
3015 }
3016 else{
3017 background[bottom]=clr;
3018 }
3019 update();
3020 }
3021
3022
3023 // Set ambient color
setAmbientColor(const FXVec4f & clr)3024 void FXGLViewer::setAmbientColor(const FXVec4f& clr){
3025 ambient=clr;
3026 update();
3027 }
3028
3029
3030 // Delegate all other messages to the GL Object
onDefault(FXObject * sender,FXSelector sel,void * ptr)3031 long FXGLViewer::onDefault(FXObject* sender,FXSelector sel,void* ptr){
3032 return selection && selection->handle(sender,sel,ptr);
3033 }
3034
3035
3036 // Change turbo mode
setTurboMode(FXbool turbo)3037 void FXGLViewer::setTurboMode(FXbool turbo){
3038 if(!turbo) doesturbo=FALSE;
3039 turbomode=turbo;
3040 }
3041
3042
3043 // Return light settings
getLight(FXLight & lite) const3044 void FXGLViewer::getLight(FXLight& lite) const {
3045 lite=light;
3046 }
3047
3048
3049 // Change light settings
setLight(const FXLight & lite)3050 void FXGLViewer::setLight(const FXLight& lite) {
3051 light=lite;
3052 update();
3053 }
3054
3055
3056 // Save object to stream
save(FXStream & store) const3057 void FXGLViewer::save(FXStream& store) const {
3058 FXGLCanvas::save(store);
3059 store << wvt.w;
3060 store << wvt.h;
3061 store << wvt.left;
3062 store << wvt.right;
3063 store << wvt.bottom;
3064 store << wvt.top;
3065 store << wvt.hither;
3066 store << wvt.yon;
3067 store << transform;
3068 store << itransform;
3069 store << projection;
3070 store << rotation;
3071 store << fov;
3072 store << zoom;
3073 store << center;
3074 store << scale;
3075 store << worldpx;
3076 store << modelpx;
3077 store << maxhits;
3078 store << diameter;
3079 store << distance;
3080 store << background[0];
3081 store << background[1];
3082 store << ambient;
3083 store << turbomode;
3084 store << help;
3085 }
3086
3087
3088
3089 // Load object from stream
load(FXStream & store)3090 void FXGLViewer::load(FXStream& store){
3091 FXGLCanvas::load(store);
3092 store >> wvt.w;
3093 store >> wvt.h;
3094 store >> wvt.left;
3095 store >> wvt.right;
3096 store >> wvt.bottom;
3097 store >> wvt.top;
3098 store >> wvt.hither;
3099 store >> wvt.yon;
3100 store >> transform;
3101 store >> itransform;
3102 store >> projection;
3103 store >> rotation;
3104 store >> fov;
3105 store >> zoom;
3106 store >> center;
3107 store >> scale;
3108 store >> worldpx;
3109 store >> modelpx;
3110 store >> maxhits;
3111 store >> diameter;
3112 store >> distance;
3113 store >> background[0];
3114 store >> background[1];
3115 store >> ambient;
3116 store >> turbomode;
3117 store >> help;
3118 }
3119
3120
3121 // Close and release any resources
~FXGLViewer()3122 FXGLViewer::~FXGLViewer(){
3123 getApp()->removeTimeout(this,ID_TIPTIMER);
3124 dropped=(FXGLObject*)-1L;
3125 selection=(FXGLObject*)-1L;
3126 scene=(FXGLObject*)-1L;
3127 }
3128
3129 }
3130