1 | /* |
2 | * fg_callbacks.c |
3 | * |
4 | * The callbacks setting methods. |
5 | * |
6 | * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. |
7 | * Written by Pawel W. Olszta, <olszta@sourceforge.net> |
8 | * Creation date: Fri Dec 3 1999 |
9 | * |
10 | * Permission is hereby granted, free of charge, to any person obtaining a |
11 | * copy of this software and associated documentation files (the "Software"), |
12 | * to deal in the Software without restriction, including without limitation |
13 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
14 | * and/or sell copies of the Software, and to permit persons to whom the |
15 | * Software is furnished to do so, subject to the following conditions: |
16 | * |
17 | * The above copyright notice and this permission notice shall be included |
18 | * in all copies or substantial portions of the Software. |
19 | * |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
21 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
23 | * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
24 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
25 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
26 | */ |
27 | |
28 | #include <GL/freeglut.h> |
29 | #include "fg_internal.h" |
30 | |
31 | /* -- INTERFACE FUNCTIONS -------------------------------------------------- */ |
32 | |
33 | |
34 | /* |
35 | * Global callbacks. |
36 | */ |
37 | /* Sets the global idle callback */ |
38 | void FGAPIENTRY glutIdleFunc( FGCBIdle callback ) |
39 | { |
40 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" ); |
41 | fgState.IdleCallback = callback; |
42 | } |
43 | |
44 | /* Creates a timer and sets its callback */ |
45 | void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int timerID ) |
46 | { |
47 | SFG_Timer *timer, *node; |
48 | |
49 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" ); |
50 | |
51 | if( (timer = fgState.FreeTimers.Last) ) |
52 | { |
53 | fgListRemove( &fgState.FreeTimers, &timer->Node ); |
54 | } |
55 | else |
56 | { |
57 | if( ! (timer = malloc(sizeof(SFG_Timer))) ) |
58 | fgError( "Fatal error: " |
59 | "Memory allocation failure in glutTimerFunc()" ); |
60 | } |
61 | |
62 | timer->Callback = callback; |
63 | timer->ID = timerID; |
64 | timer->TriggerTime = fgElapsedTime() + timeOut; |
65 | |
66 | /* Insert such that timers are sorted by end-time */ |
67 | for( node = fgState.Timers.First; node; node = node->Node.Next ) |
68 | { |
69 | if( node->TriggerTime > timer->TriggerTime ) |
70 | break; |
71 | } |
72 | |
73 | fgListInsert( &fgState.Timers, &node->Node, &timer->Node ); |
74 | } |
75 | |
76 | /* Deprecated version of glutMenuStatusFunc callback setting method */ |
77 | void FGAPIENTRY ( FGCBMenuState callback ) |
78 | { |
79 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStateFunc" ); |
80 | fgState.MenuStateCallback = callback; |
81 | } |
82 | |
83 | /* Sets the global menu status callback for the current window */ |
84 | void FGAPIENTRY ( FGCBMenuStatus callback ) |
85 | { |
86 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFunc" ); |
87 | fgState.MenuStatusCallback = callback; |
88 | } |
89 | |
90 | |
91 | /* |
92 | * Menu specific callbacks. |
93 | */ |
94 | /* Callback upon menu destruction */ |
95 | void FGAPIENTRY ( FGCBDestroy callback ) |
96 | { |
97 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" ); |
98 | if( fgStructure.CurrentMenu ) |
99 | fgStructure.CurrentMenu->Destroy = callback; |
100 | } |
101 | |
102 | |
103 | /* |
104 | * All of the window-specific callbacks setting methods can be generalized to this: |
105 | */ |
106 | #define SET_CALLBACK(a) \ |
107 | do \ |
108 | { \ |
109 | if( fgStructure.CurrentWindow == NULL ) \ |
110 | return; \ |
111 | SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback ); \ |
112 | } while( 0 ) |
113 | /* |
114 | * And almost every time the callback setter function can be implemented like this: |
115 | */ |
116 | #define IMPLEMENT_CALLBACK_FUNC_2NAME(a,b) \ |
117 | void FGAPIENTRY glut##a##Func( FGCB##b callback ) \ |
118 | { \ |
119 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" ); \ |
120 | SET_CALLBACK( b ); \ |
121 | } |
122 | #define IMPLEMENT_CALLBACK_FUNC(a) IMPLEMENT_CALLBACK_FUNC_2NAME(a,a) |
123 | |
124 | /* Implement all these callback setter functions... */ |
125 | IMPLEMENT_CALLBACK_FUNC(Position) |
126 | IMPLEMENT_CALLBACK_FUNC(Keyboard) |
127 | IMPLEMENT_CALLBACK_FUNC(KeyboardExt) |
128 | IMPLEMENT_CALLBACK_FUNC(KeyboardDown) |
129 | IMPLEMENT_CALLBACK_FUNC(KeyboardUp) |
130 | IMPLEMENT_CALLBACK_FUNC(Special) |
131 | IMPLEMENT_CALLBACK_FUNC(SpecialUp) |
132 | IMPLEMENT_CALLBACK_FUNC(Mouse) |
133 | IMPLEMENT_CALLBACK_FUNC(MouseWheel) |
134 | IMPLEMENT_CALLBACK_FUNC(Motion) |
135 | IMPLEMENT_CALLBACK_FUNC_2NAME(PassiveMotion,Passive) |
136 | IMPLEMENT_CALLBACK_FUNC(Entry) |
137 | /* glutWMCloseFunc is an alias for glutCloseFunc; both set the window's Destroy callback */ |
138 | IMPLEMENT_CALLBACK_FUNC_2NAME(Close,Destroy) |
139 | IMPLEMENT_CALLBACK_FUNC_2NAME(WMClose,Destroy) |
140 | IMPLEMENT_CALLBACK_FUNC(OverlayDisplay) |
141 | IMPLEMENT_CALLBACK_FUNC(WindowStatus) |
142 | IMPLEMENT_CALLBACK_FUNC(ButtonBox) |
143 | IMPLEMENT_CALLBACK_FUNC(Dials) |
144 | IMPLEMENT_CALLBACK_FUNC(TabletMotion) |
145 | IMPLEMENT_CALLBACK_FUNC(TabletButton) |
146 | IMPLEMENT_CALLBACK_FUNC(MultiEntry) |
147 | IMPLEMENT_CALLBACK_FUNC(MultiButton) |
148 | IMPLEMENT_CALLBACK_FUNC(MultiMotion) |
149 | IMPLEMENT_CALLBACK_FUNC(MultiPassive) |
150 | IMPLEMENT_CALLBACK_FUNC(InitContext) |
151 | IMPLEMENT_CALLBACK_FUNC(AppStatus) |
152 | |
153 | |
154 | |
155 | /* |
156 | * Sets the Display callback for the current window |
157 | */ |
158 | void FGAPIENTRY glutDisplayFunc( FGCBDisplay callback ) |
159 | { |
160 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" ); |
161 | if( !callback ) |
162 | fgError( "Fatal error in program. NULL display callback not " |
163 | "permitted in GLUT 3.0+ or freeglut 2.0.1+" ); |
164 | SET_CALLBACK( Display ); |
165 | } |
166 | |
167 | void fghDefaultReshape(int width, int height) |
168 | { |
169 | glViewport( 0, 0, width, height ); |
170 | } |
171 | |
172 | void FGAPIENTRY glutReshapeFunc( FGCBReshape callback ) |
173 | { |
174 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" ); |
175 | |
176 | if( !callback ) |
177 | callback = fghDefaultReshape; |
178 | |
179 | SET_CALLBACK( Reshape ); |
180 | } |
181 | |
182 | /* |
183 | * Sets the Visibility callback for the current window. |
184 | * NB: the Visibility func is deprecated in favor of the WindowStatus func, |
185 | * which provides more detail. The visibility func callback is implemented |
186 | * as a translation step from the windowStatus func. When the user sets the |
187 | * windowStatus func, any visibility func is overwritten. |
188 | * DEVELOPER NOTE: in the library, only invoke the window status func, this |
189 | * gets automatically translated to the visibility func if thats what the |
190 | * user has set. |
191 | * window status is kind of anemic on win32 as there are no window messages |
192 | * to notify us that the window is covered by other windows or not. |
193 | * Should one want to query this, see |
194 | * http://stackoverflow.com/questions/5445889/get-which-process-window-is-actually-visible-in-c-sharp |
195 | * for an implementation outline (but it would be polling based, not push based). |
196 | */ |
197 | static void fghVisibility( int status ) |
198 | { |
199 | int vis_status; |
200 | |
201 | FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" ); |
202 | freeglut_return_if_fail( fgStructure.CurrentWindow ); |
203 | |
204 | /* Translate window status func states to visibility states */ |
205 | if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) ) |
206 | vis_status = GLUT_NOT_VISIBLE; |
207 | else /* GLUT_FULLY_RETAINED, GLUT_PARTIALLY_RETAINED */ |
208 | vis_status = GLUT_VISIBLE; |
209 | |
210 | INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( vis_status ) ); |
211 | } |
212 | |
213 | void FGAPIENTRY glutVisibilityFunc( FGCBVisibility callback ) |
214 | { |
215 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" ); |
216 | SET_CALLBACK( Visibility ); |
217 | |
218 | if( callback ) |
219 | glutWindowStatusFunc( fghVisibility ); |
220 | else |
221 | glutWindowStatusFunc( NULL ); |
222 | } |
223 | |
224 | /* |
225 | * Sets the joystick callback and polling rate for the current window |
226 | */ |
227 | void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval ) |
228 | { |
229 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" ); |
230 | fgInitialiseJoysticks (); |
231 | |
232 | if ( ( |
233 | fgStructure.CurrentWindow->State.JoystickPollRate <= 0 || /* Joystick callback was disabled */ |
234 | !FETCH_WCB(*fgStructure.CurrentWindow,Joystick) |
235 | ) && |
236 | ( |
237 | callback && ( pollInterval > 0 ) /* but is now enabled */ |
238 | ) ) |
239 | ++fgState.NumActiveJoysticks; |
240 | else if ( ( |
241 | fgStructure.CurrentWindow->State.JoystickPollRate > 0 && /* Joystick callback was enabled */ |
242 | FETCH_WCB(*fgStructure.CurrentWindow,Joystick) |
243 | ) && |
244 | ( |
245 | !callback || ( pollInterval <= 0 ) /* but is now disabled */ |
246 | ) ) |
247 | --fgState.NumActiveJoysticks; |
248 | |
249 | SET_CALLBACK( Joystick ); |
250 | fgStructure.CurrentWindow->State.JoystickPollRate = pollInterval; |
251 | |
252 | /* set last poll time such that joystick will be polled asap */ |
253 | fgStructure.CurrentWindow->State.JoystickLastPoll = fgElapsedTime(); |
254 | if (fgStructure.CurrentWindow->State.JoystickLastPoll < pollInterval) |
255 | fgStructure.CurrentWindow->State.JoystickLastPoll = 0; |
256 | else |
257 | fgStructure.CurrentWindow->State.JoystickLastPoll -= pollInterval; |
258 | } |
259 | |
260 | |
261 | |
262 | /* |
263 | * Sets the spaceball motion callback for the current window |
264 | */ |
265 | void FGAPIENTRY glutSpaceballMotionFunc( FGCBSpaceMotion callback ) |
266 | { |
267 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" ); |
268 | fgInitialiseSpaceball(); |
269 | |
270 | SET_CALLBACK( SpaceMotion ); |
271 | } |
272 | |
273 | /* |
274 | * Sets the spaceball rotate callback for the current window |
275 | */ |
276 | void FGAPIENTRY glutSpaceballRotateFunc( FGCBSpaceRotation callback ) |
277 | { |
278 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" ); |
279 | fgInitialiseSpaceball(); |
280 | |
281 | SET_CALLBACK( SpaceRotation ); |
282 | } |
283 | |
284 | /* |
285 | * Sets the spaceball button callback for the current window |
286 | */ |
287 | void FGAPIENTRY glutSpaceballButtonFunc( FGCBSpaceButton callback ) |
288 | { |
289 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" ); |
290 | fgInitialiseSpaceball(); |
291 | |
292 | SET_CALLBACK( SpaceButton ); |
293 | } |
294 | |
295 | /*** END OF FILE ***/ |
296 | |