1 /*
2 * gauche-glut.c - Gauche GLUT binding
3 *
4 * Copyright (c) 2001-2014 Shiro Kawai <shiro@acm.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the authors nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <gauche.h>
35 #include <gauche/extend.h>
36
37 #if MacOSX
38 #include <GLUT/glut.h>
39 #else
40 #include <GL/glut.h>
41 #endif
42 #include "gauche-glut.h"
43
44 extern void Scm_Init_glut_lib(ScmModule *mod);
45
46 /*================================================================
47 * Glut font
48 */
49
50 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_GlutFontClass, NULL);
51
makeGlutFont(void * ptr)52 static ScmObj makeGlutFont(void *ptr)
53 {
54 ScmGlutFont *gf = SCM_NEW(ScmGlutFont);
55 SCM_SET_CLASS(gf, SCM_CLASS_GLUT_FONT);
56 gf->font = ptr;
57 return SCM_OBJ(gf);
58 }
59
60 /*================================================================
61 * Callback support.
62 *
63 * Glut callbacks are associated to the "current window".
64 * unfortunately the callback interface doesn't allow us
65 * to pass extra data pointer, so our C callback routine
66 * doesn't know which Scheme closure to be called. We maintain
67 * that information in our table.
68 *
69 * TODO: We don't want to use Scm_ApplyRec, for we need to cons
70 * the arguments (display is ok, but motion and passiveMotion generates
71 * garbages which will eventurally trigger GC.) Rewrite *_cb functions
72 * after we implement Scm_ApplyRec0, Scm_ApplyRec1, .., etc. in
73 * Gauche core.
74 */
75
76 static ScmObj ScmGlutCallbackTable = SCM_UNDEFINED; /* set by init routine */
77
get_callback(int type)78 static ScmObj get_callback(int type)
79 {
80 int win = glutGetWindow();
81 ScmObj entry = Scm_HashTableRef(SCM_HASH_TABLE(ScmGlutCallbackTable),
82 SCM_MAKE_INT(win), SCM_FALSE);
83 SCM_ASSERT(type >= 0 && type < SCM_GLUT_NUM_WINDOW_CBS);
84 if (SCM_VECTORP(entry)) {
85 return SCM_VECTOR_ELEMENT(entry, type);
86 } else {
87 return SCM_FALSE;
88 }
89 }
90
91 #define define_callback(name, num, arglist, args) \
92 static void SCM_CPP_CAT(name, _cb) arglist \
93 { \
94 ScmObj cb = get_callback(SCM_CPP_CAT(SCM_GLUT_CB_, num)); \
95 if (!SCM_FALSEP(cb)) { \
96 Scm_ApplyRec(cb, args); \
97 } \
98 }
99
100 define_callback(display, DISPLAY, (void), SCM_NIL)
101
102
103 define_callback(overlay_display, OVERLAY_DISPLAY, (void), SCM_NIL)
104 define_callback(reshape, RESHAPE, (int w, int h),
105 SCM_LIST2(SCM_MAKE_INT(w), SCM_MAKE_INT(h)));
106 define_callback(keyboard, KEYBOARD, (unsigned char key, int w, int h),
107 SCM_LIST3(SCM_MAKE_INT(key), SCM_MAKE_INT(w), SCM_MAKE_INT(h)))
108 define_callback(keyboard_up, KEYBOARD_UP, (unsigned char key, int w, int h),
109 SCM_LIST3(SCM_MAKE_INT(key), SCM_MAKE_INT(w), SCM_MAKE_INT(h)))
110 define_callback(mouse, MOUSE, (int button, int state, int x, int y),
111 SCM_LIST4(SCM_MAKE_INT(button), SCM_MAKE_INT(state),
112 SCM_MAKE_INT(x), SCM_MAKE_INT(y)))
113 define_callback(motion, MOTION, (int x, int y),
114 SCM_LIST2(SCM_MAKE_INT(x), SCM_MAKE_INT(y)))
115 define_callback(passive_motion, PASSIVE_MOTION, (int x, int y),
116 SCM_LIST2(SCM_MAKE_INT(x), SCM_MAKE_INT(y)))
117 define_callback(visibility, VISIBILITY, (int state),
118 SCM_LIST1(SCM_MAKE_INT(state)))
119 define_callback(entry, ENTRY, (int state),
120 SCM_LIST1(SCM_MAKE_INT(state)))
121 define_callback(special, SPECIAL, (int key, int w, int h),
122 SCM_LIST3(SCM_MAKE_INT(key), SCM_MAKE_INT(w), SCM_MAKE_INT(h)))
123 define_callback(special_up, SPECIAL_UP, (int key, int w, int h),
124 SCM_LIST3(SCM_MAKE_INT(key), SCM_MAKE_INT(w), SCM_MAKE_INT(h)))
125 define_callback(spaceball_motion, SPACEBALL_MOTION, (int x, int y, int z),
126 SCM_LIST3(SCM_MAKE_INT(x), SCM_MAKE_INT(y), SCM_MAKE_INT(z)))
127 define_callback(spaceball_rotate, SPACEBALL_ROTATE, (int x, int y, int z),
128 SCM_LIST3(SCM_MAKE_INT(x), SCM_MAKE_INT(y), SCM_MAKE_INT(z)))
129 define_callback(spaceball_button, SPACEBALL_BUTTON, (int button, int state),
130 SCM_LIST2(SCM_MAKE_INT(button), SCM_MAKE_INT(state)))
131 define_callback(button_box, BUTTON_BOX, (int button, int state),
132 SCM_LIST2(SCM_MAKE_INT(button), SCM_MAKE_INT(state)))
133 define_callback(dials, DIALS, (int dial, int value),
134 SCM_LIST2(SCM_MAKE_INT(dial), SCM_MAKE_INT(value)))
135 define_callback(tablet_motion, TABLET_MOTION, (int x, int y),
136 SCM_LIST2(SCM_MAKE_INT(x), SCM_MAKE_INT(y)))
137 define_callback(tablet_button, TABLET_BUTTON,
138 (int button, int state, int x, int y),
139 SCM_LIST4(SCM_MAKE_INT(button),
140 SCM_MAKE_INT(state),
141 SCM_MAKE_INT(x),
142 SCM_MAKE_INT(y)))
143 define_callback(menu_status, MENU_STATUS, (int status, int x, int y),
144 SCM_LIST3(SCM_MAKE_INT(status),
145 SCM_MAKE_INT(x), SCM_MAKE_INT(y)))
146 define_callback(window_status, WINDOW_STATUS, (int status),
147 SCM_LIST1(SCM_MAKE_INT(status)))
148 define_callback(joystick, JOYSTICK, (unsigned int mask, int x, int y, int z),
149 SCM_LIST4(SCM_MAKE_INT(mask),
150 SCM_MAKE_INT(x), SCM_MAKE_INT(y), SCM_MAKE_INT(z)))
151
152 /* global callbacks */
153 static ScmObj idle_closure = SCM_FALSE;
154
idle_cb(void)155 static void idle_cb(void)
156 {
157 if (!SCM_FALSEP(idle_closure)) {
158 Scm_ApplyRec(idle_closure, SCM_NIL);
159 }
160 }
161
162 static ScmObj timer_closure = SCM_FALSE;
163
timer_cb(int value)164 static void timer_cb(int value)
165 {
166 if (!SCM_FALSEP(timer_closure)) {
167 Scm_ApplyRec(timer_closure, SCM_LIST1(Scm_MakeInteger(value)));
168 }
169 }
170
171
172 /* NB: these functions are new addition by freeglut. we provide
173 dummy functions for older versions. */
174 #if !(GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13)
glutKeyboardUpFunc(void (* fn)(unsigned char,int,int))175 static void glutKeyboardUpFunc(void (*fn)(unsigned char, int, int))
176 {
177 Scm_Warn("glutKeyboardUpFunc unsupported in this version of GLUT");
178 }
glutSpecialUpFunc(void (* fn)(int,int,int))179 static void glutSpecialUpFunc(void (*fn)(int, int, int))
180 {
181 Scm_Warn("glutSpecialUpFunc unsupported in this version of GLUT");
182 }
glutJoystickFunc(void (* fn)(unsigned int,int,int,int),int interval)183 static void glutJoystickFunc(void (*fn)(unsigned int, int, int, int),
184 int interval)
185 {
186 Scm_Warn("glutJoystickFunc unsupported in this version of GLUT");
187 }
glutWindowStatusFunc(void (* fn)(unsigned int,int,int,int))188 static void glutWindowStatusFunc(void (*fn)(unsigned int, int, int, int))
189 {
190 Scm_Warn("glutWindowStatusFunc unsupported in this version of GLUT");
191 }
192 #endif
193
194
195 #define define_registrar(glutfn, cbname) \
196 static void SCM_CPP_CAT(register_, cbname)(int flag, int xtra) \
197 { \
198 if (flag) { \
199 glutfn(SCM_CPP_CAT(cbname, _cb)); \
200 } else { \
201 glutfn(NULL); \
202 } \
203 }
204
define_registrar(glutDisplayFunc,display)205 define_registrar(glutDisplayFunc, display)
206 define_registrar(glutOverlayDisplayFunc, overlay_display)
207 define_registrar(glutReshapeFunc, reshape)
208 define_registrar(glutKeyboardFunc, keyboard)
209 define_registrar(glutKeyboardUpFunc, keyboard_up)
210 define_registrar(glutMouseFunc, mouse)
211 define_registrar(glutMotionFunc, motion)
212 define_registrar(glutPassiveMotionFunc, passive_motion)
213 define_registrar(glutVisibilityFunc, visibility)
214 define_registrar(glutEntryFunc, entry)
215 define_registrar(glutSpecialFunc, special)
216 define_registrar(glutSpecialUpFunc, special_up)
217 define_registrar(glutSpaceballMotionFunc, spaceball_motion)
218 define_registrar(glutSpaceballRotateFunc, spaceball_rotate)
219 define_registrar(glutSpaceballButtonFunc, spaceball_button)
220 define_registrar(glutButtonBoxFunc, button_box)
221 define_registrar(glutDialsFunc, dials)
222 define_registrar(glutTabletMotionFunc, tablet_motion)
223 define_registrar(glutTabletButtonFunc, tablet_button)
224 define_registrar(glutMenuStatusFunc, menu_status)
225 define_registrar(glutWindowStatusFunc, window_status)
226
227 /* joystick fn is a bit different */
228 static void register_joystick(int flag, int interval)
229 {
230 if (flag) {
231 glutJoystickFunc(joystick_cb, interval);
232 } else {
233 glutJoystickFunc(NULL, interval);
234 }
235 }
236
237
238 /* NB: order must match SCM_GLUT_CB_* enums */
239 static void (*registrars[])(int flag, int xtra) = {
240 register_display,
241 register_overlay_display,
242 register_reshape,
243 register_keyboard,
244 register_mouse,
245 register_motion,
246 register_passive_motion,
247 register_visibility,
248 register_entry,
249 register_special,
250 register_spaceball_motion,
251 register_spaceball_rotate,
252 register_spaceball_button,
253 register_button_box,
254 register_dials,
255 register_tablet_motion,
256 register_tablet_button,
257 register_menu_status,
258 register_window_status,
259 register_keyboard_up,
260 register_special_up,
261 register_joystick,
262 };
263
264 /*
265 * External entry to manage registering callbacks
266 * 'xtra1' and 'xtra2' are ignored by most callbacks; only the two callbacks
267 * use them:
268 * glutTimerFunc: xtra1 for millliseconds, xtra2 for value
269 * glutJoystickFunc: xtra1 for interval
270 */
Scm_GlutRegisterCallback(int type,ScmObj closure,int xtra1,int xtra2)271 void Scm_GlutRegisterCallback(int type, ScmObj closure, int xtra1, int xtra2)
272 {
273 SCM_ASSERT(type >= 0 && type < SCM_GLUT_NUM_CBS);
274 if (type < SCM_GLUT_NUM_WINDOW_CBS) {
275 int win = glutGetWindow();
276 ScmObj entry = Scm_HashTableRef(SCM_HASH_TABLE(ScmGlutCallbackTable),
277 SCM_MAKE_INT(win), SCM_FALSE);
278
279 if (SCM_EQ(entry, SCM_FALSE)) {
280 entry = Scm_MakeVector(SCM_GLUT_NUM_WINDOW_CBS, SCM_FALSE);
281 Scm_HashTableSet(SCM_HASH_TABLE(ScmGlutCallbackTable),
282 SCM_MAKE_INT(win), entry, 0);
283 }
284 SCM_VECTOR_ELEMENT(entry, type) = closure;
285 registrars[type](!SCM_FALSEP(closure), xtra1);
286 } else if (type == SCM_GLUT_CB_IDLE) {
287 idle_closure = closure;
288 if (SCM_FALSEP(closure)) {
289 glutIdleFunc(NULL);
290 } else {
291 glutIdleFunc(idle_cb);
292 }
293 } else {
294 timer_closure = closure;
295 if (!SCM_FALSEP(closure)) {
296 glutTimerFunc(xtra1, timer_cb, xtra2);
297 }
298 }
299 }
300
301 /*================================================================
302 * Initialization
303 */
Scm_Init_libgauche_glut(void)304 void Scm_Init_libgauche_glut(void)
305 {
306 ScmModule *mod;
307 SCM_INIT_EXTENSION(libgauche_glut);
308 mod = SCM_MODULE(SCM_FIND_MODULE("gl.glut", TRUE));
309 Scm_Init_glut_lib(mod);
310
311 /* Callback table */
312 ScmGlutCallbackTable = Scm_MakeHashTableSimple(SCM_HASH_EQV, 0);
313
314 /* Glut built-in fonts */
315 #define DEFFONT(name) Scm_DefineConst(mod, SCM_SYMBOL(SCM_INTERN(#name)), makeGlutFont(name))
316 /* Stroke font constants (use these in GLUT program). */
317 DEFFONT(GLUT_STROKE_ROMAN);
318 DEFFONT(GLUT_STROKE_MONO_ROMAN);
319
320 /* Bitmap font constants (use these in GLUT program). */
321 DEFFONT(GLUT_BITMAP_9_BY_15);
322 DEFFONT(GLUT_BITMAP_8_BY_13);
323 DEFFONT(GLUT_BITMAP_TIMES_ROMAN_10);
324 DEFFONT(GLUT_BITMAP_TIMES_ROMAN_24);
325 #if (GLUT_API_VERSION >= 3)
326 DEFFONT(GLUT_BITMAP_HELVETICA_10);
327 DEFFONT(GLUT_BITMAP_HELVETICA_12);
328 DEFFONT(GLUT_BITMAP_HELVETICA_18);
329 #endif
330 }
331