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