diff --git a/.autotest b/.autotest new file mode 100644 index 0000000..9147a57 --- /dev/null +++ b/.autotest @@ -0,0 +1,29 @@ +require 'autotest/restart' + +Autotest.add_hook :initialize do |at| + at.add_exception /\.git/ + at.add_exception /doc/ + at.add_exception /examples/ + at.add_exception /utils/ + at.add_exception /website/ + + at.add_mapping(/^lib\/.*(\.bundle|so|dll)$/) do |filename, match| + possible = File.basename(filename, match[1]) + at.files_matching %r%^test/test_#{possible}% + end + + def at.path_to_classname s + sep = File::SEPARATOR + n = s.sub(/^test#{sep}test_(.*)\.rb/, '\1') + c = if n =~ /^(glu?)_?(.*)/ then + "#{$1.capitalize}#{$2.split(/_|(\d+)/).map { |seg| seg.capitalize }.join}" + end + + "Test#{c}" + end +end + +Autotest.add_hook :run_command do |at| + at.unit_diff = 'cat' + system Gem.ruby, Gem.bin_path('rake', 'rake'), 'compile' +end diff --git a/.gemtest b/.gemtest new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39447a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.swp +/TAGS +/lib/glut/*.so +/lib/glut/*.bundle +/pkg +/tmp diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5f515e7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: ruby +rvm: +# - "1.9.3" + - "2.0.0" +# - jruby-19mode # JRuby in 1.9 mode +# - rbx-19mode +before_install: + - gem install hoe rake-compiler; + - sudo apt-get install xpra xserver-xorg-video-dummy freeglut3-dev; +before_script: + - "xpra --xvfb=\"Xorg +extension GLX -config `pwd`/test/dummy.xorg.conf -logfile ${HOME}/.xpra/xorg.log\" start :9" +script: "env DISPLAY=:9 rake test" +after_script: + - "xpra stop :9" + - "cat ~/.xpra/*" diff --git a/History.rdoc b/History.rdoc new file mode 100644 index 0000000..ba7b3c9 --- /dev/null +++ b/History.rdoc @@ -0,0 +1,25 @@ +=== 8.3.0 / 2017-05-30 + +* Add ruby-2.4 to binary windows gems and remove ruby-1.9. +* Add support for source gems on RubyInstaller-2.4 and MSYS2. + +=== 8.2.2 / 2016-01-21 + +* Add ruby-2.2 and 2.3 to binary windows gems. +* Fix compilation on OS-X. Github #2 + +=== 8.2.1 / 2014-10-06 + +* Add ruby-2.1 to binary windows gems. +* Fix segmentation fault in glutKeyboardUpFunc callback + +=== 8.2.0 / 2014-03-14 + +* Add x64-mingw platform for cross build and add ruby-2.0.0 to binary gems. +* Update to freeglut-2.8.1 for cross build. +* Don't pollute the global namespace. Use GLUT namespace. +* Replace deprecated rb_thread_blocking_region() by rb_thread_call_with_gvl() + +=== 8.1.0 / 2013-03-03 + +* Moved glut into a standalone gem. diff --git a/MIT-LICENSE b/MIT-LICENSE new file mode 100644 index 0000000..0860220 --- /dev/null +++ b/MIT-LICENSE @@ -0,0 +1,18 @@ + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/Manifest.txt b/Manifest.txt new file mode 100644 index 0000000..0362286 --- /dev/null +++ b/Manifest.txt @@ -0,0 +1,16 @@ +.autotest +.gemtest +.gitignore +.travis.yml +History.rdoc +MIT-LICENSE +Manifest.txt +README.rdoc +Rakefile +ext/glut/common.h +ext/glut/extconf.rb +ext/glut/glut.c +ext/glut/glut_callbacks.c +ext/glut/glut_ext.c +lib/glut.rb +lib/glut/dummy.rb diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 0000000..e71fc5e --- /dev/null +++ b/README.rdoc @@ -0,0 +1,77 @@ += glut + +== Description + +Glut bindings for OpenGL. To be used with the {opengl}[https://github.com/larskanis/opengl] gem. + +== Features and Problems + +* available for Windows, Linux and OS X + +== Requirements + +* Ruby 1.9.2+ + * see {0.7}[https://github.com/archSeer/opengl/tree/0.7] for Ruby 1.8.x compatible branch +* (free-)GLUT development files installed + +== Install + + gem install glut + +== Cross compiling for Windows + +Using rake-compiler a cross compiled opengl gem can be build on a Linux or MacOS X +host for the win32 platform. The generated gem is statically linked against +libfreeglut. Freeglut is downloaded and compiled from the sources. +There are no runtime dependencies to any but the standard Windows +DLLs. + +Install mingw32 or w64 using the instructions in rake-compiler's README. +For Debian/Ubuntu it is apt-get install gcc-mingw-w64 . + +Download and cross compile ruby 1.9 for win32 with: + + rake-compiler cross-ruby VERSION=1.9.3-p0 + +Download and cross compile opengl for win32: + + rake cross native gem + +or with custom versions: + + rake cross native gem RUBY_CC_VERSION=1.9.3 LIBFREEGLUT_VERSION=2.8.0 + +If everything works, there should be ruby-opengl-VERSION-x86-mingw32.gem in the pkg +directory. + + +== License + +(The MIT License) + +Copyright (c) Blaž Hrastnik (current maintainer) +Copyright (c) Eric Hodel (current maintainer) +Copyright (c) Alain Hoang (previous maintainer) +Copyright (c) Jan Dvorak (contributor) +Copyright (c) Minh Thu Vo (contributor) +Copyright (c) James Adam (contributor) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d4a7a30 --- /dev/null +++ b/Rakefile @@ -0,0 +1,79 @@ +# -*- coding: UTF-8 -*- +# -*-ruby-*- +# +# Copyright (C) 2006 John M. Gabriele +# Copyright (C) Eric Hodel +# +# This program is distributed under the terms of the MIT license. +# See the included MIT-LICENSE file for the terms of this license. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +require 'hoe' +require 'rake/extensiontask' + +hoe = Hoe.spec 'glut' do + developer 'Eric Hodel', 'drbrain@segment7.net' + developer 'Lars Kanis', 'lars@greiz-reinsdorf.de' + developer 'Blaž Hrastnik', 'speed.the.bboy@gmail.com' + developer 'Alain Hoang', '' + developer 'Jan Dvorak', '' + developer 'Minh Thu Vo', '' + developer 'James Adam', '' + + self.readme_file = 'README.rdoc' + self.history_file = 'History.rdoc' + self.extra_rdoc_files = FileList['*.rdoc'] + + extra_dev_deps << ['rake-compiler', '~> 1.0'] + extra_dev_deps << ['rake-compiler-dock', '~> 0.6.0'] + extra_dev_deps << ['mini_portile2', '~> 2.1'] + + self.spec_extras = { + :extensions => %w[ext/glut/extconf.rb], + :required_ruby_version => '>= 1.9.2', + :metadata => {'msys2_mingw_dependencies' => 'freeglut'}, + } +end + +Rake::ExtensionTask.new 'glut', hoe.spec do |ext| + ext.lib_dir = 'lib/glut' + + ext.cross_compile = true + ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] + ext.cross_config_options += [ + "--enable-win32-cross", + ] + ext.cross_compiling do |spec| + # The fat binary gem doesn't depend on the freeglut package, since it bundles the library. + spec.metadata.delete('msys2_mingw_dependencies') + end +end + + +# To reduce the gem file size strip mingw32 dlls before packaging +ENV['RUBY_CC_VERSION'].to_s.split(':').each do |ruby_version| + task "copy:glut:x86-mingw32:#{ruby_version}" do |t| + sh "i686-w64-mingw32-strip -S tmp/x86-mingw32/stage/lib/glut/#{ruby_version[/^\d+\.\d+/]}/glut.so" + end + + task "copy:glut:x64-mingw32:#{ruby_version}" do |t| + sh "x86_64-w64-mingw32-strip -S tmp/x64-mingw32/stage/lib/glut/#{ruby_version[/^\d+\.\d+/]}/glut.so" + end +end + +desc "Build windows binary gems per rake-compiler-dock." +task "gem:windows" do + require "rake_compiler_dock" + RakeCompilerDock.sh <<-EOT + rake cross native gem MAKE='nice make -j`nproc`' + EOT +end + +task :test => :compile diff --git a/ext/glut/common.h b/ext/glut/common.h new file mode 100644 index 0000000..e570693 --- /dev/null +++ b/ext/glut/common.h @@ -0,0 +1,68 @@ +/* + * Last edit by previous maintainer: + * 2000/01/06 16:37:43, kusano + * + * Copyright (C) 1999 - 2005 Yoshi + * Copyright (C) 2006 John M. Gabriele + * Copyright (C) 2007 James Adam + * Copyright (C) 2007 Jan Dvorak + * + * This program is distributed under the terms of the MIT license. + * See the included MIT-LICENSE file for the terms of this license. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include +#include "extconf.h" + +#ifdef HAVE_GL_FREEGLUT_H +#include +#endif + +#ifdef HAVE_GL_GLUT_H +#include +#endif + +#ifdef HAVE_GLUT_GLUT_H +#include +#endif + +#ifndef GLUTCALLBACK +#define GLUTCALLBACK +#endif + +#ifdef HAVE_WINDOWS_H +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +/* these two macros are cast to a 32 bit type in the places they are used */ +#ifndef RARRAY_LENINT +#define RARRAY_LENINT RARRAY_LEN +#endif + +/* GLUT */ + +#define GLUT_SIMPLE_FUNCTION(_name_) \ +static VALUE \ +glut_##_name_(obj) \ +VALUE obj; \ +{ \ + glut##_name_(); \ + return Qnil; \ +} + +VALUE rb_glut_check_callback(VALUE, VALUE); + +#endif diff --git a/ext/glut/extconf.rb b/ext/glut/extconf.rb new file mode 100644 index 0000000..96a97a7 --- /dev/null +++ b/ext/glut/extconf.rb @@ -0,0 +1,72 @@ +require 'mkmf' + +def have_framework(fw, &b) + checking_for fw do + src = cpp_include("#{fw}/#{fw}.h") << "\n" "int main(void){return 0;}" + if try_link(src, opt = "-ObjC -framework #{fw}", &b) + $defs.push(format("-DHAVE_FRAMEWORK_%s", fw.tr_cpp)) + $LDFLAGS << " " << opt + true + else + false + end + end +end unless respond_to? :have_framework + +if enable_config('win32-cross') + require "rubygems" + gem "mini_portile2", "~> 2.0" + require "mini_portile2" + + LIBFREEGLUT_VERSION = ENV['LIBFREEGLUT_VERSION'] || '2.8.1' + LIBFREEGLUT_SOURCE_URI = "http://downloads.sourceforge.net/project/freeglut/freeglut/#{LIBFREEGLUT_VERSION}/freeglut-#{LIBFREEGLUT_VERSION}.tar.gz" + + recipe = MiniPortile.new("libglut", LIBFREEGLUT_VERSION) + recipe.files = [LIBFREEGLUT_SOURCE_URI] + recipe.target = portsdir = File.expand_path('../../../ports', __FILE__) + # Prefer host_alias over host in order to use i586-mingw32msvc as + # correct compiler prefix for cross build, but use host if not set. + recipe.host = RbConfig::CONFIG["host_alias"].empty? ? RbConfig::CONFIG["host"] : RbConfig::CONFIG["host_alias"] + recipe.configure_options = [ + "--enable-static", + "--target=#{recipe.host}", + "--host=#{recipe.host}", + ] + + checkpoint = File.join(portsdir, "#{recipe.name}-#{recipe.version}-#{recipe.host}.installed") + unless File.exist?(checkpoint) + recipe.cook + # --disable-static can not be used since it breaks the freeglut build, + # but to enforce static linking, we delete the import lib. + FileUtils.rm File.join(recipe.path, "lib", "libglut.dll.a") + FileUtils.touch checkpoint + end + recipe.activate + + $defs.push "-DFREEGLUT_EXPORTS" + dir_config('freeglut', "#{recipe.path}/include", "#{recipe.path}/lib") + + # libfreeglut is linked to gdi32 and winmm + have_library( 'gdi32', 'CreateDC' ) && append_library( $libs, 'gdi32' ) + have_library( 'winmm', 'timeBeginPeriod' ) && append_library( $libs, 'winmm' ) +end + +ok = + (have_library('opengl32.lib', 'glVertex3d') && have_library('glut32.lib', 'gluSolidTeapot')) || + (have_library('opengl32') && (have_library('glut') || have_library('freeglut'))) || + (have_library('GL', 'glVertex3d') && have_library('glut', 'glutSolidTeapot')) || + (have_framework('OpenGL') && have_framework('GLUT') && have_framework('Cocoa')) + +ok &&= + have_header('GL/freeglut.h') || + have_header('GL/glut.h') || + have_header('GLUT/glut.h') # OS X + +if String === ?a then + $defs.push "-DHAVE_SINGLE_BYTE_STRINGS" +end + +if ok then + create_header + create_makefile 'glut/glut' +end diff --git a/ext/glut/glut.c b/ext/glut/glut.c new file mode 100644 index 0000000..daa0df6 --- /dev/null +++ b/ext/glut/glut.c @@ -0,0 +1,1152 @@ +/* + * Last edit by previous maintainer: + * 2004/03/02 01:13:06, yoshi + * + * Copyright (C) 1999 - 2005 Yoshi + * Copyright (C) 2005 James Adam + * Copyright (C) 2006 John M. Gabriele + * Copyright (C) 2007 Jan Dvorak + * + * This program is distributed under the terms of the MIT license. + * See the included COPYRIGHT file for the terms of this license. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common.h" +extern void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1, + rb_unblock_function_t *ubf, void *data2); + +static VALUE menu_callback = Qnil; +static ID call_id; /* 'call' method id */ + +VALUE +rb_glut_check_callback(VALUE self, VALUE callback) +{ + VALUE inspect; + + if (NIL_P(callback)) + return callback; + + if (rb_respond_to(callback, call_id)) + return callback; + + if (SYMBOL_P(callback)) + return rb_obj_method(self, callback); + + inspect = rb_inspect(callback); + rb_raise(rb_eArgError, "%s must respond to call", StringValueCStr(inspect)); +} + +static VALUE glut_Init( int argc, VALUE * argv, VALUE obj) +{ + int largc; + char** largv; + VALUE new_argv; + VALUE orig_arg; + int i; + + if (rb_scan_args(argc, argv, "01", &orig_arg) == 0) + orig_arg = rb_eval_string("[$0] + ARGV"); + else + Check_Type(orig_arg, T_ARRAY); + + /* converts commandline parameters from ruby to C, passes them + to glutInit and returns the parameters stripped of glut-specific + commands ("-display","-geometry" etc.) */ + largc = (int)RARRAY_LENINT(orig_arg); + largv = ALLOCA_N(char*, largc); + for (i = 0; i < largc; i++) + largv[i] = StringValueCStr(RARRAY_PTR(orig_arg)[i]); + + glutInit(&largc, largv); + + new_argv = rb_ary_new2(largc); + for (i = 0; i < largc; i++) + rb_ary_push(new_argv,rb_str_new2(largv[i])); + + rb_ary_shift(new_argv); + + return new_argv; +} + +static VALUE glut_InitDisplayMode(obj,arg1) +VALUE obj,arg1; +{ + unsigned int mode; + mode = (unsigned int)NUM2INT(arg1); + glutInitDisplayMode(mode); + return Qnil; +} + +static VALUE +glut_InitDisplayString(obj,arg1) +VALUE obj,arg1; +{ + Check_Type(arg1,T_STRING); + glutInitDisplayString(RSTRING_PTR(arg1)); + return Qnil; +} + +static VALUE +glut_InitWindowPosition(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int x,y; + x = NUM2INT(arg1); + y = NUM2INT(arg2); + glutInitWindowPosition(x,y); + return Qnil; +} + +static VALUE +glut_InitWindowSize(obj, arg1, arg2) +VALUE obj,arg1,arg2; +{ + int width,height; + width = NUM2INT(arg1); + height = NUM2INT(arg2); + glutInitWindowSize(width,height); + return Qnil; +} + +void *glut_MainLoop0(void *ignored) { + glutMainLoop(); + + return NULL; /* never reached */ +} + +static VALUE +glut_MainLoop(void) { + rb_thread_call_without_gvl(glut_MainLoop0, NULL, NULL, NULL); + + return Qnil; /* never reached */ +} + +static VALUE +glut_CheckLoop(void) { + rb_warn("calling fake CheckLoop implementation which never returns"); + + glut_MainLoop(); + + return Qnil; +} + +/* GLUT window sub-API. */ +static VALUE glut_CreateWindow(argc, argv, obj) +int argc; +VALUE* argv; +VALUE obj; +{ + int ret; + VALUE title; + rb_scan_args(argc, argv, "01", &title); + if (argc == 0) + title = rb_eval_string("$0"); + Check_Type(title,T_STRING); + ret = glutCreateWindow(RSTRING_PTR(title)); + return INT2NUM(ret); +} + +static VALUE +glut_CreateSubWindow(obj,arg1,arg2,arg3,arg4,arg5) +VALUE obj,arg1,arg2,arg3,arg4,arg5; +{ + int win, x, y, width, height; + int ret; + win = NUM2INT(arg1); + x = NUM2INT(arg2); + y = NUM2INT(arg3); + width = NUM2INT(arg4); + height = NUM2INT(arg5); + ret = glutCreateSubWindow(win, x, y, width, height); + return INT2NUM(ret); +} + +static VALUE +glut_DestroyWindow(obj,arg1) +VALUE obj,arg1; +{ + int win; + win = NUM2INT(arg1); + glutDestroyWindow(win); + return Qnil; +} + +GLUT_SIMPLE_FUNCTION(PostRedisplay) +GLUT_SIMPLE_FUNCTION(SwapBuffers) + +static VALUE +glut_GetWindow(obj) +VALUE obj; +{ + int ret; + ret = glutGetWindow(); + return INT2NUM(ret); +} + +static VALUE +glut_SetWindow(obj,arg1) +VALUE obj,arg1; +{ + int win; + win = NUM2INT(arg1); + glutSetWindow(win); + return Qnil; +} + +static VALUE +glut_SetWindowTitle(obj,arg1) +VALUE obj,arg1; +{ + Check_Type(arg1,T_STRING); + glutSetWindowTitle(RSTRING_PTR(arg1)); + return Qnil; +} + +static VALUE +glut_SetIconTitle(obj, arg1) +VALUE obj,arg1; +{ + Check_Type(arg1,T_STRING); + glutSetIconTitle(RSTRING_PTR(arg1)); + return Qnil; +} + +static VALUE +glut_PositionWindow(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int x,y; + x = NUM2INT(arg1); + y = NUM2INT(arg2); + glutPositionWindow(x,y); + return Qnil; +} + +static VALUE +glut_ReshapeWindow(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int width,height; + width = NUM2INT(arg1); + height = NUM2INT(arg2); + glutReshapeWindow(width, height); + return Qnil; +} + +GLUT_SIMPLE_FUNCTION(PopWindow) +GLUT_SIMPLE_FUNCTION(PushWindow) +GLUT_SIMPLE_FUNCTION(IconifyWindow) +GLUT_SIMPLE_FUNCTION(ShowWindow) +GLUT_SIMPLE_FUNCTION(HideWindow) +GLUT_SIMPLE_FUNCTION(FullScreen) + +static VALUE +glut_SetCursor(obj,arg1) +VALUE obj,arg1; +{ + int cursor; + cursor = NUM2INT(arg1); + glutSetCursor(cursor); + return Qnil; +} + +static VALUE +glut_WarpPointer(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int x,y; + x = NUM2INT(arg1); + y = NUM2INT(arg2); + glutWarpPointer(x,y); + return Qnil; +} + +/* GLUT overlay sub-API. */ +GLUT_SIMPLE_FUNCTION(EstablishOverlay) +GLUT_SIMPLE_FUNCTION(RemoveOverlay) +GLUT_SIMPLE_FUNCTION(PostOverlayRedisplay) +GLUT_SIMPLE_FUNCTION(ShowOverlay) +GLUT_SIMPLE_FUNCTION(HideOverlay) + +static VALUE +glut_UseLayer(obj,arg1) +VALUE obj, arg1; +{ + GLenum layer; + layer = (GLenum)NUM2INT(arg1); + glutUseLayer(layer); + return Qnil; +} + +static void GLUTCALLBACK +glut_CreateMenuCallback(int value) +{ + VALUE func; + int menu; + menu = glutGetMenu(); + func = rb_ary_entry(menu_callback, menu); + + rb_funcall(func, call_id, 1, INT2NUM(value)); +} + +static VALUE +glut_CreateMenu(VALUE obj, VALUE callback) { + int menu; + + callback = rb_glut_check_callback(obj, callback); + + if (NIL_P(callback)) + menu = glutCreateMenu(NULL); + else + menu = glutCreateMenu(glut_CreateMenuCallback); + + rb_ary_store(menu_callback, menu, callback); + + return INT2FIX(menu); +} + +static VALUE +glut_DestroyMenu(obj,arg1) +VALUE obj,arg1; +{ + int menu; + menu = NUM2INT(arg1); + glutDestroyMenu(menu); + //rb_hash_aset(g_menucallback, menu, Qnil); + //rb_hash_aset(g_menuargs, menu, Qnil); + return Qnil; +} + +static VALUE +glut_GetMenu(obj) +VALUE obj; +{ + int ret; + ret = glutGetMenu(); + return INT2NUM(ret); +} + +static VALUE +glut_SetMenu(obj,arg1) +VALUE obj,arg1; +{ + glutSetMenu(NUM2INT(arg1)); + return Qnil; +} + +static VALUE +glut_AddMenuEntry(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + Check_Type(arg1,T_STRING); + glutAddMenuEntry(RSTRING_PTR(arg1), NUM2INT(arg2)); + return Qnil; +} + +static VALUE +glut_AddSubMenu(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + Check_Type(arg1,T_STRING); + glutAddSubMenu(RSTRING_PTR(arg1), NUM2INT(arg2)); + return Qnil; +} + +static VALUE glut_ChangeToMenuEntry(obj,arg1,arg2,arg3) +VALUE obj,arg1,arg2,arg3; +{ + Check_Type(arg2,T_STRING); + glutChangeToMenuEntry(NUM2INT(arg1), RSTRING_PTR(arg2), NUM2INT(arg3)); + return Qnil; +} + +static VALUE glut_ChangeToSubMenu(obj,arg1,arg2,arg3) +VALUE obj,arg1,arg2,arg3; +{ + Check_Type(arg2,T_STRING); + glutChangeToSubMenu(NUM2INT(arg1), RSTRING_PTR(arg2), NUM2INT(arg3)); + return Qnil; +} + +static VALUE glut_RemoveMenuItem( VALUE obj, VALUE arg1 ) +{ + glutRemoveMenuItem(NUM2INT(arg1)); + return Qnil; +} + +static VALUE +glut_AttachMenu(obj,arg1) +VALUE obj, arg1; +{ + glutAttachMenu(NUM2INT(arg1)); + return Qnil; +} + +static VALUE +glut_DetachMenu(obj,arg1) +VALUE obj, arg1; +{ + glutDetachMenu(NUM2INT(arg1)); + return Qnil; +} + +/* GLUT color index sub-API. */ +static VALUE +glut_SetColor(obj,arg1,arg2,arg3,arg4) +VALUE obj,arg1,arg2,arg3,arg4; +{ + int set; + GLfloat red; + GLfloat green; + GLfloat blue; + set = NUM2INT(arg1); + red = (GLfloat)NUM2DBL(arg2); + green = (GLfloat)NUM2DBL(arg3); + blue = (GLfloat)NUM2DBL(arg4); + glutSetColor(set, red, green, blue); + return Qnil; +} + +static VALUE +glut_GetColor(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int ndx; + int component; + GLfloat ret; + ndx = NUM2INT(arg1); + component = NUM2INT(arg2); + ret = (GLfloat)glutGetColor(ndx, component); + return rb_float_new(ret); +} + +static VALUE +glut_CopyColormap(obj,arg1) +VALUE obj,arg1; +{ + int win; + win = NUM2INT(arg1); + glutCopyColormap(win); + return Qnil; +} + +/* GLUT state retrieval sub-API. */ +static VALUE +glut_Get(obj,arg1) +VALUE obj,arg1; +{ + GLenum type; + int ret; + type = (GLenum)NUM2INT(arg1); + ret = glutGet(type); + return INT2NUM(ret); +} + +static VALUE +glut_DeviceGet(obj,arg1) +VALUE obj,arg1; +{ + GLenum type; + int ret; + type = (GLenum)NUM2INT(arg1); + ret = glutDeviceGet(type); + return INT2NUM(ret); +} + +/* GLUT extension support sub-API */ +static VALUE +glut_ExtensionSupported(obj,arg1) +VALUE obj,arg1; +{ + int ret; + Check_Type(arg1,T_STRING); + ret = glutExtensionSupported(RSTRING_PTR(arg1)); + return INT2NUM(ret); +} + +static VALUE +glut_GetModifiers(obj) +VALUE obj; +{ + int ret; + ret = glutGetModifiers(); + return INT2NUM(ret); +} + +static VALUE +glut_LayerGet(obj,arg1) +VALUE obj,arg1; +{ + GLenum type; + int ret; + type = (GLenum)NUM2INT(arg1); + ret = glutLayerGet(type); + return INT2NUM(ret); +} + +/* GLUT font sub-API */ + +/* Some glut implementations define font enums as addresses of local functions + * which are then called by glut internally. This may lead to crashes or bus + * errors on some platforms, so to be safe we hardcode the values passed + * to/from ruby + */ + +static inline void * bitmap_font_map(int f) +{ + switch (f) { + case 0: return (void *)GLUT_BITMAP_9_BY_15; + case 1: return (void *)GLUT_BITMAP_8_BY_13; + case 2: return (void *)GLUT_BITMAP_TIMES_ROMAN_10; + case 3: return (void *)GLUT_BITMAP_TIMES_ROMAN_24; + case 4: return (void *)GLUT_BITMAP_HELVETICA_10; + case 5: return (void *)GLUT_BITMAP_HELVETICA_12; + case 6: return (void *)GLUT_BITMAP_HELVETICA_18; + default: + rb_raise(rb_eArgError, "Unsupported font %d", f); + } + + return (void *) 0; /* not reached */ +} + +static inline void * stroke_font_map(int f) +{ + switch (f) { + case 7: return (void *)GLUT_STROKE_ROMAN; + case 8: return (void *)GLUT_STROKE_MONO_ROMAN; + default: + rb_raise(rb_eArgError, "Unsupported font %d", f); + } + + return (void *) 0; /* not reached */ +} + +static VALUE +glut_BitmapCharacter(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int character; + int font; + font = NUM2INT(arg1); + character = NUM2INT(arg2); + glutBitmapCharacter(bitmap_font_map(font),character); + return Qnil; +} + +static VALUE +glut_BitmapWidth(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int font; + int character; + int ret; + font = NUM2INT(arg1); + character = NUM2INT(arg2); + ret = glutBitmapWidth(bitmap_font_map(font), character); + return INT2NUM(ret); +} + +static VALUE +glut_StrokeCharacter(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int font; + int character; + font = NUM2INT(arg1); + character = NUM2INT(arg2); + glutStrokeCharacter(stroke_font_map(font), character); + return Qnil; +} + +static VALUE +glut_StrokeWidth(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int font; + int character; + int ret; + font = NUM2INT(arg1); + character = NUM2INT(arg2); + ret = glutStrokeWidth(stroke_font_map(font), character); + return INT2NUM(ret); +} + +static VALUE +glut_BitmapLength(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int font; + int ret; + Check_Type(arg2,T_STRING); + font = NUM2INT(arg1); + ret = glutBitmapLength(bitmap_font_map(font), (const unsigned char*)RSTRING_PTR(arg2)); + return INT2NUM(ret); +} + +static VALUE +glut_StrokeLength(obj,arg1,arg2) +VALUE obj,arg1,arg2; +{ + int font; + int ret; + Check_Type(arg2,T_STRING); + font = NUM2INT(arg1); + ret = glutStrokeLength(stroke_font_map(font), (const unsigned char*)RSTRING_PTR(arg2)); + return INT2NUM(ret); +} + +/* GLUT pre-built models sub-API */ +static VALUE +glut_WireSphere(obj,arg1,arg2,arg3) +VALUE obj,arg1,arg2,arg3; +{ + GLdouble radius; + GLint slices; + GLint stacks; + radius = (GLdouble)NUM2DBL(arg1); + slices = (GLint)NUM2INT(arg2); + stacks = (GLint)NUM2INT(arg3); + glutWireSphere(radius, slices, stacks); + return Qnil; +} + +static VALUE +glut_SolidSphere(obj,arg1,arg2,arg3) +VALUE obj,arg1,arg2,arg3; +{ + GLdouble radius; + GLint slices; + GLint stacks; + radius = (GLdouble)NUM2DBL(arg1); + slices = (GLint)NUM2INT(arg2); + stacks = (GLint)NUM2INT(arg3); + glutSolidSphere(radius, slices, stacks); + return Qnil; +} + +static VALUE +glut_WireCone(obj,arg1,arg2,arg3,arg4) +VALUE obj,arg1,arg2,arg3,arg4; +{ + GLdouble base; + GLdouble height; + GLint slices; + GLint stacks; + base = (GLdouble)NUM2DBL(arg1); + height = (GLdouble)NUM2DBL(arg2); + slices = (GLint)NUM2INT(arg3); + stacks = (GLint)NUM2INT(arg4); + glutWireCone(base, height, slices, stacks); + return Qnil; +} + +static VALUE +glut_SolidCone(obj,arg1,arg2,arg3,arg4) +VALUE obj,arg1,arg2,arg3,arg4; +{ + GLdouble base; + GLdouble height; + GLint slices; + GLint stacks; + base = (GLdouble)NUM2DBL(arg1); + height = (GLdouble)NUM2DBL(arg2); + slices = (GLint)NUM2INT(arg3); + stacks = (GLint)NUM2INT(arg4); + glutSolidCone(base, height, slices, stacks); + return Qnil; +} + +static VALUE +glut_WireCube(obj,arg1) +VALUE obj,arg1; +{ + GLdouble size; + size = (GLdouble)NUM2DBL(arg1); + glutWireCube(size); + return Qnil; +} + +static VALUE +glut_SolidCube(obj,arg1) +VALUE obj,arg1; +{ + GLdouble size; + size = (GLdouble)NUM2DBL(arg1); + glutSolidCube(size); + return Qnil; +} + +static VALUE +glut_WireTorus(obj,arg1,arg2,arg3,arg4) +VALUE obj,arg1,arg2,arg3,arg4; +{ + GLdouble innerRadius; + GLdouble outerRadius; + GLint sides; + GLint rings; + innerRadius = (GLdouble)NUM2DBL(arg1); + outerRadius = (GLdouble)NUM2DBL(arg2); + sides = (GLint)NUM2INT(arg3); + rings = (GLint)NUM2INT(arg4); + glutWireTorus(innerRadius, outerRadius, sides, rings); + return Qnil; +} + +static VALUE +glut_SolidTorus(obj,arg1,arg2,arg3,arg4) +VALUE obj,arg1,arg2,arg3,arg4; +{ + GLdouble innerRadius; + GLdouble outerRadius; + GLint sides; + GLint rings; + innerRadius = (GLdouble)NUM2DBL(arg1); + outerRadius = (GLdouble)NUM2DBL(arg2); + sides = (GLint)NUM2INT(arg3); + rings = (GLint)NUM2INT(arg4); + glutSolidTorus(innerRadius, outerRadius, sides, rings); + return Qnil; +} + +GLUT_SIMPLE_FUNCTION(WireDodecahedron) +GLUT_SIMPLE_FUNCTION(SolidDodecahedron) +GLUT_SIMPLE_FUNCTION(WireOctahedron) +GLUT_SIMPLE_FUNCTION(SolidOctahedron) +GLUT_SIMPLE_FUNCTION(WireTetrahedron) +GLUT_SIMPLE_FUNCTION(SolidTetrahedron) +GLUT_SIMPLE_FUNCTION(WireIcosahedron) +GLUT_SIMPLE_FUNCTION(SolidIcosahedron) + +static VALUE +glut_WireTeapot(obj,arg1) +VALUE obj,arg1; +{ + GLdouble size; + size = (GLdouble)NUM2DBL(arg1); + glutWireTeapot(size); + return Qnil; +} + +static VALUE +glut_SolidTeapot(obj,arg1) +VALUE obj,arg1; +{ + GLdouble size; + size = (GLdouble)NUM2DBL(arg1); + glutSolidTeapot(size); + return Qnil; +} + +/* GLUT video resize sub-API. */ +static VALUE +glut_VideoResizeGet(obj,arg1) +VALUE obj,arg1; +{ + GLenum param; + int ret; + param = (GLenum)NUM2INT(arg1); + ret = glutVideoResizeGet(param); + return INT2NUM(ret); +} + +GLUT_SIMPLE_FUNCTION(SetupVideoResizing) +GLUT_SIMPLE_FUNCTION(StopVideoResizing) + +static VALUE +glut_VideoResize(obj,arg1,arg2,arg3,arg4) +VALUE obj,arg1,arg2,arg3,arg4; +{ + int x; + int y; + int width; + int height; + x = NUM2INT(arg1); + y = NUM2INT(arg2); + width = NUM2INT(arg3); + height = NUM2INT(arg4); + glutVideoResize(x,y, width, height); + return Qnil; +} + +static VALUE +glut_VideoPan(obj,arg1,arg2,arg3,arg4) +VALUE obj,arg1,arg2,arg3,arg4; +{ + int x; + int y; + int width; + int height; + x = NUM2INT(arg1); + y = NUM2INT(arg2); + width = NUM2INT(arg3); + height = NUM2INT(arg4); + glutVideoPan(x,y, width, height); + return Qnil; +} + +/* GLUT debugging sub-API. */ +GLUT_SIMPLE_FUNCTION(ReportErrors) + +static VALUE +glut_GameModeString(obj,arg1) +VALUE obj,arg1; +{ + Check_Type(arg1,T_STRING); + glutGameModeString((const char*)RSTRING_PTR(arg1)); + return Qnil; +} + +GLUT_SIMPLE_FUNCTION(EnterGameMode) +GLUT_SIMPLE_FUNCTION(LeaveGameMode) + +static VALUE +glut_GameModeGet(obj,arg1) +VALUE obj,arg1; +{ + GLenum info; + int i; + info = (GLenum)NUM2INT(arg1); + i = glutGameModeGet(info); + return INT2NUM(i); +} + +static VALUE +glut_SetKeyRepeat(obj,arg1) +VALUE obj,arg1; +{ + GLenum repeatMode; + repeatMode = (int) NUM2INT(arg1); + glutSetKeyRepeat(repeatMode); + return Qnil; +} + +static VALUE +glut_IgnoreKeyRepeat(obj,arg1) +VALUE obj,arg1; +{ + GLenum ignore; + ignore = (int) NUM2INT(arg1); + glutIgnoreKeyRepeat(ignore); + return Qnil; +} + +static VALUE +glut_PostWindowOverlayRedisplay(obj,arg1) +VALUE obj,arg1; +{ + int win; + win = (int) NUM2INT(arg1); + glutPostWindowOverlayRedisplay(win); + return Qnil; +} + +static VALUE +glut_PostWindowRedisplay(obj,arg1) +VALUE obj,arg1; +{ + int win; + win = (int) NUM2INT(arg1); + glutPostWindowRedisplay(win); + return Qnil; +} + +void Init_glut_callbacks(void); +void Init_glut_ext(void); + +void Init_glut() { + VALUE mGlut; + + call_id = rb_intern("call"); + mGlut = rb_define_module("Glut"); + + menu_callback = rb_ary_new(); + rb_global_variable(&menu_callback); + + rb_define_module_function(mGlut, "glutInit", glut_Init, -1); + rb_define_module_function(mGlut, "glutInitDisplayMode", glut_InitDisplayMode, 1); + rb_define_module_function(mGlut, "glutInitDisplayString", glut_InitDisplayString, 1); + rb_define_module_function(mGlut, "glutInitWindowPosition", glut_InitWindowPosition, 2); + rb_define_module_function(mGlut, "glutInitWindowSize", glut_InitWindowSize, 2); + rb_define_module_function(mGlut, "glutMainLoop", glut_MainLoop, 0); + rb_define_module_function(mGlut, "glutCheckLoop", glut_CheckLoop, 0); + rb_define_module_function(mGlut, "glutGameModeString", glut_GameModeString, 1); + rb_define_module_function(mGlut, "glutEnterGameMode", glut_EnterGameMode, 0); + rb_define_module_function(mGlut, "glutLeaveGameMode", glut_LeaveGameMode, 0); + rb_define_module_function(mGlut, "glutCreateWindow", glut_CreateWindow, -1); + rb_define_module_function(mGlut, "glutCreateSubWindow", glut_CreateSubWindow, 5); + rb_define_module_function(mGlut, "glutDestroyWindow", glut_DestroyWindow, 1); + rb_define_module_function(mGlut, "glutPostRedisplay", glut_PostRedisplay, 0); + rb_define_module_function(mGlut, "glutSwapBuffers", glut_SwapBuffers, 0); + rb_define_module_function(mGlut, "glutGetWindow", glut_GetWindow, 0); + rb_define_module_function(mGlut, "glutSetWindow", glut_SetWindow, 1); + rb_define_module_function(mGlut, "glutSetWindowTitle", glut_SetWindowTitle, 1); + rb_define_module_function(mGlut, "glutSetIconTitle", glut_SetIconTitle, 1); + rb_define_module_function(mGlut, "glutPositionWindow", glut_PositionWindow, 2); + rb_define_module_function(mGlut, "glutReshapeWindow", glut_ReshapeWindow, 2); + rb_define_module_function(mGlut, "glutPopWindow", glut_PopWindow, 0); + rb_define_module_function(mGlut, "glutPushWindow", glut_PushWindow, 0); + rb_define_module_function(mGlut, "glutIconifyWindow", glut_IconifyWindow, 0); + rb_define_module_function(mGlut, "glutShowWindow", glut_ShowWindow, 0); + rb_define_module_function(mGlut, "glutHideWindow", glut_HideWindow, 0); + rb_define_module_function(mGlut, "glutFullScreen", glut_FullScreen, 0); + rb_define_module_function(mGlut, "glutSetCursor", glut_SetCursor, 1); + rb_define_module_function(mGlut, "glutWarpPointer", glut_WarpPointer, 2); + rb_define_module_function(mGlut, "glutEstablishOverlay", glut_EstablishOverlay, 0); + rb_define_module_function(mGlut, "glutRemoveOverlay", glut_RemoveOverlay, 0); + rb_define_module_function(mGlut, "glutUseLayer", glut_UseLayer, 1); + rb_define_module_function(mGlut, "glutPostOverlayRedisplay", glut_PostOverlayRedisplay, 0); + rb_define_module_function(mGlut, "glutShowOverlay", glut_ShowOverlay, 0); + rb_define_module_function(mGlut, "glutHideOverlay", glut_HideOverlay, 0); + rb_define_module_function(mGlut, "glutCreateMenu", glut_CreateMenu, 1); + rb_define_module_function(mGlut, "glutDestroyMenu", glut_DestroyMenu, 1); + rb_define_module_function(mGlut, "glutGetMenu", glut_GetMenu, 0); + rb_define_module_function(mGlut, "glutSetMenu", glut_SetMenu, 1); + rb_define_module_function(mGlut, "glutAddMenuEntry", glut_AddMenuEntry, 2); + rb_define_module_function(mGlut, "glutAddSubMenu", glut_AddSubMenu, 2); + rb_define_module_function(mGlut, "glutChangeToMenuEntry", glut_ChangeToMenuEntry, 3); + rb_define_module_function(mGlut, "glutChangeToSubMenu", glut_ChangeToSubMenu, 3); + rb_define_module_function(mGlut, "glutRemoveMenuItem", glut_RemoveMenuItem, 1); + rb_define_module_function(mGlut, "glutAttachMenu", glut_AttachMenu, 1); + rb_define_module_function(mGlut, "glutDetachMenu", glut_DetachMenu, 1); + rb_define_module_function(mGlut, "glutSetColor", glut_SetColor, 4); + rb_define_module_function(mGlut, "glutGetColor", glut_GetColor, 2); + rb_define_module_function(mGlut, "glutCopyColormap", glut_CopyColormap, 1); + rb_define_module_function(mGlut, "glutGet", glut_Get, 1); + rb_define_module_function(mGlut, "glutDeviceGet", glut_DeviceGet, 1); + rb_define_module_function(mGlut, "glutExtensionSupported", glut_ExtensionSupported, 1); + rb_define_module_function(mGlut, "glutGetModifiers", glut_GetModifiers, 0); + rb_define_module_function(mGlut, "glutLayerGet", glut_LayerGet, 1); + rb_define_module_function(mGlut, "glutBitmapCharacter", glut_BitmapCharacter, 2); + rb_define_module_function(mGlut, "glutBitmapWidth", glut_BitmapWidth, 2); + rb_define_module_function(mGlut, "glutStrokeCharacter", glut_StrokeCharacter, 2); + rb_define_module_function(mGlut, "glutStrokeWidth", glut_StrokeWidth, 2); + rb_define_module_function(mGlut, "glutBitmapLength", glut_BitmapLength, 2); + rb_define_module_function(mGlut, "glutStrokeLength", glut_StrokeLength, 2); + rb_define_module_function(mGlut, "glutWireSphere", glut_WireSphere, 3); + rb_define_module_function(mGlut, "glutSolidSphere", glut_SolidSphere, 3); + rb_define_module_function(mGlut, "glutWireCone", glut_WireCone, 4); + rb_define_module_function(mGlut, "glutSolidCone", glut_SolidCone, 4); + rb_define_module_function(mGlut, "glutWireCube", glut_WireCube, 1); + rb_define_module_function(mGlut, "glutSolidCube", glut_SolidCube, 1); + rb_define_module_function(mGlut, "glutWireTorus", glut_WireTorus, 4); + rb_define_module_function(mGlut, "glutSolidTorus", glut_SolidTorus, 4); + rb_define_module_function(mGlut, "glutWireDodecahedron", glut_WireDodecahedron, 0); + rb_define_module_function(mGlut, "glutSolidDodecahedron", glut_SolidDodecahedron, 0); + rb_define_module_function(mGlut, "glutWireTeapot", glut_WireTeapot, 1); + rb_define_module_function(mGlut, "glutSolidTeapot", glut_SolidTeapot, 1); + rb_define_module_function(mGlut, "glutWireOctahedron", glut_WireOctahedron, 0); + rb_define_module_function(mGlut, "glutSolidOctahedron", glut_SolidOctahedron, 0); + rb_define_module_function(mGlut, "glutWireTetrahedron", glut_WireTetrahedron, 0); + rb_define_module_function(mGlut, "glutSolidTetrahedron", glut_SolidTetrahedron, 0); + rb_define_module_function(mGlut, "glutWireIcosahedron", glut_WireIcosahedron, 0); + rb_define_module_function(mGlut, "glutSolidIcosahedron", glut_SolidIcosahedron, 0); + rb_define_module_function(mGlut, "glutVideoResizeGet", glut_VideoResizeGet, 1); + rb_define_module_function(mGlut, "glutSetupVideoResizing", glut_SetupVideoResizing, 0); + rb_define_module_function(mGlut, "glutStopVideoResizing", glut_StopVideoResizing, 0); + rb_define_module_function(mGlut, "glutVideoResize", glut_VideoResize, 4); + rb_define_module_function(mGlut, "glutVideoPan", glut_VideoPan, 4); + rb_define_module_function(mGlut, "glutReportErrors", glut_ReportErrors, 0); + + rb_define_module_function(mGlut, "glutGameModeGet", glut_GameModeGet, 1); + rb_define_module_function(mGlut, "glutSetKeyRepeat", glut_SetKeyRepeat, 1); + rb_define_module_function(mGlut, "glutIgnoreKeyRepeat", glut_IgnoreKeyRepeat, 1); + rb_define_module_function(mGlut, "glutPostWindowOverlayRedisplay", glut_PostWindowOverlayRedisplay, 1); + rb_define_module_function(mGlut, "glutPostWindowRedisplay", glut_PostWindowRedisplay, 1); + + rb_define_const(mGlut, "GLUT_API_VERSION", INT2NUM(GLUT_API_VERSION)); + rb_define_const(mGlut, "GLUT_XLIB_IMPLEMENTATION", INT2NUM(GLUT_XLIB_IMPLEMENTATION)); + rb_define_const(mGlut, "GLUT_RGB", INT2NUM(GLUT_RGB)); + rb_define_const(mGlut, "GLUT_RGBA", INT2NUM(GLUT_RGBA)); + rb_define_const(mGlut, "GLUT_INDEX", INT2NUM(GLUT_INDEX)); + rb_define_const(mGlut, "GLUT_SINGLE", INT2NUM(GLUT_SINGLE)); + rb_define_const(mGlut, "GLUT_DOUBLE", INT2NUM(GLUT_DOUBLE)); + rb_define_const(mGlut, "GLUT_ACCUM", INT2NUM(GLUT_ACCUM)); + rb_define_const(mGlut, "GLUT_ALPHA", INT2NUM(GLUT_ALPHA)); + rb_define_const(mGlut, "GLUT_DEPTH", INT2NUM(GLUT_DEPTH)); + rb_define_const(mGlut, "GLUT_STENCIL", INT2NUM(GLUT_STENCIL)); + rb_define_const(mGlut, "GLUT_MULTISAMPLE", INT2NUM(GLUT_MULTISAMPLE)); + rb_define_const(mGlut, "GLUT_STEREO", INT2NUM(GLUT_STEREO)); + rb_define_const(mGlut, "GLUT_LUMINANCE", INT2NUM(GLUT_LUMINANCE)); + rb_define_const(mGlut, "GLUT_LEFT_BUTTON", INT2NUM(GLUT_LEFT_BUTTON)); + rb_define_const(mGlut, "GLUT_MIDDLE_BUTTON", INT2NUM(GLUT_MIDDLE_BUTTON)); + rb_define_const(mGlut, "GLUT_RIGHT_BUTTON", INT2NUM(GLUT_RIGHT_BUTTON)); + rb_define_const(mGlut, "GLUT_DOWN", INT2NUM(GLUT_DOWN)); + rb_define_const(mGlut, "GLUT_UP", INT2NUM(GLUT_UP)); + rb_define_const(mGlut, "GLUT_KEY_F1", INT2NUM(GLUT_KEY_F1)); + rb_define_const(mGlut, "GLUT_KEY_F2", INT2NUM(GLUT_KEY_F2)); + rb_define_const(mGlut, "GLUT_KEY_F3", INT2NUM(GLUT_KEY_F3)); + rb_define_const(mGlut, "GLUT_KEY_F4", INT2NUM(GLUT_KEY_F4)); + rb_define_const(mGlut, "GLUT_KEY_F5", INT2NUM(GLUT_KEY_F5)); + rb_define_const(mGlut, "GLUT_KEY_F6", INT2NUM(GLUT_KEY_F6)); + rb_define_const(mGlut, "GLUT_KEY_F7", INT2NUM(GLUT_KEY_F7)); + rb_define_const(mGlut, "GLUT_KEY_F8", INT2NUM(GLUT_KEY_F8)); + rb_define_const(mGlut, "GLUT_KEY_F9", INT2NUM(GLUT_KEY_F9)); + rb_define_const(mGlut, "GLUT_KEY_F10", INT2NUM(GLUT_KEY_F10)); + rb_define_const(mGlut, "GLUT_KEY_F11", INT2NUM(GLUT_KEY_F11)); + rb_define_const(mGlut, "GLUT_KEY_F12", INT2NUM(GLUT_KEY_F12)); + rb_define_const(mGlut, "GLUT_KEY_LEFT", INT2NUM(GLUT_KEY_LEFT)); + rb_define_const(mGlut, "GLUT_KEY_UP", INT2NUM(GLUT_KEY_UP)); + rb_define_const(mGlut, "GLUT_KEY_RIGHT", INT2NUM(GLUT_KEY_RIGHT)); + rb_define_const(mGlut, "GLUT_KEY_DOWN", INT2NUM(GLUT_KEY_DOWN)); + rb_define_const(mGlut, "GLUT_KEY_PAGE_UP", INT2NUM(GLUT_KEY_PAGE_UP)); + rb_define_const(mGlut, "GLUT_KEY_PAGE_DOWN", INT2NUM(GLUT_KEY_PAGE_DOWN)); + rb_define_const(mGlut, "GLUT_KEY_HOME", INT2NUM(GLUT_KEY_HOME)); + rb_define_const(mGlut, "GLUT_KEY_END", INT2NUM(GLUT_KEY_END)); + rb_define_const(mGlut, "GLUT_KEY_INSERT", INT2NUM(GLUT_KEY_INSERT)); + rb_define_const(mGlut, "GLUT_LEFT", INT2NUM(GLUT_LEFT)); + rb_define_const(mGlut, "GLUT_ENTERED", INT2NUM(GLUT_ENTERED)); + rb_define_const(mGlut, "GLUT_MENU_NOT_IN_USE", INT2NUM(GLUT_MENU_NOT_IN_USE)); + rb_define_const(mGlut, "GLUT_MENU_IN_USE", INT2NUM(GLUT_MENU_IN_USE)); + rb_define_const(mGlut, "GLUT_NOT_VISIBLE", INT2NUM(GLUT_NOT_VISIBLE)); + rb_define_const(mGlut, "GLUT_VISIBLE", INT2NUM(GLUT_VISIBLE)); + rb_define_const(mGlut, "GLUT_HIDDEN", INT2NUM(GLUT_HIDDEN)); + rb_define_const(mGlut, "GLUT_FULLY_RETAINED", INT2NUM(GLUT_FULLY_RETAINED)); + rb_define_const(mGlut, "GLUT_PARTIALLY_RETAINED", INT2NUM(GLUT_PARTIALLY_RETAINED)); + rb_define_const(mGlut, "GLUT_FULLY_COVERED", INT2NUM(GLUT_FULLY_COVERED)); + rb_define_const(mGlut, "GLUT_RED", INT2NUM(GLUT_RED)); + rb_define_const(mGlut, "GLUT_GREEN", INT2NUM(GLUT_GREEN)); + rb_define_const(mGlut, "GLUT_BLUE", INT2NUM(GLUT_BLUE)); + rb_define_const(mGlut, "GLUT_WINDOW_X", INT2NUM(GLUT_WINDOW_X)); + rb_define_const(mGlut, "GLUT_WINDOW_Y", INT2NUM(GLUT_WINDOW_Y)); + rb_define_const(mGlut, "GLUT_WINDOW_WIDTH", INT2NUM(GLUT_WINDOW_WIDTH)); + rb_define_const(mGlut, "GLUT_WINDOW_HEIGHT", INT2NUM(GLUT_WINDOW_HEIGHT)); + rb_define_const(mGlut, "GLUT_WINDOW_BUFFER_SIZE", INT2NUM(GLUT_WINDOW_BUFFER_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_STENCIL_SIZE", INT2NUM(GLUT_WINDOW_STENCIL_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_DEPTH_SIZE", INT2NUM(GLUT_WINDOW_DEPTH_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_RED_SIZE", INT2NUM(GLUT_WINDOW_RED_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_GREEN_SIZE", INT2NUM(GLUT_WINDOW_GREEN_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_BLUE_SIZE", INT2NUM(GLUT_WINDOW_BLUE_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_ALPHA_SIZE", INT2NUM(GLUT_WINDOW_ALPHA_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_ACCUM_RED_SIZE", INT2NUM(GLUT_WINDOW_ACCUM_RED_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_ACCUM_GREEN_SIZE", INT2NUM(GLUT_WINDOW_ACCUM_GREEN_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_ACCUM_BLUE_SIZE", INT2NUM(GLUT_WINDOW_ACCUM_BLUE_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_ACCUM_ALPHA_SIZE", INT2NUM(GLUT_WINDOW_ACCUM_ALPHA_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_DOUBLEBUFFER", INT2NUM(GLUT_WINDOW_DOUBLEBUFFER)); + rb_define_const(mGlut, "GLUT_WINDOW_RGBA", INT2NUM(GLUT_WINDOW_RGBA)); + rb_define_const(mGlut, "GLUT_WINDOW_PARENT", INT2NUM(GLUT_WINDOW_PARENT)); + rb_define_const(mGlut, "GLUT_WINDOW_NUM_CHILDREN", INT2NUM(GLUT_WINDOW_NUM_CHILDREN)); + rb_define_const(mGlut, "GLUT_WINDOW_COLORMAP_SIZE", INT2NUM(GLUT_WINDOW_COLORMAP_SIZE)); + rb_define_const(mGlut, "GLUT_WINDOW_NUM_SAMPLES", INT2NUM(GLUT_WINDOW_NUM_SAMPLES)); + rb_define_const(mGlut, "GLUT_WINDOW_STEREO", INT2NUM(GLUT_WINDOW_STEREO)); + rb_define_const(mGlut, "GLUT_WINDOW_CURSOR", INT2NUM(GLUT_WINDOW_CURSOR)); + rb_define_const(mGlut, "GLUT_SCREEN_WIDTH", INT2NUM(GLUT_SCREEN_WIDTH)); + rb_define_const(mGlut, "GLUT_SCREEN_HEIGHT", INT2NUM(GLUT_SCREEN_HEIGHT)); + rb_define_const(mGlut, "GLUT_SCREEN_WIDTH_MM", INT2NUM(GLUT_SCREEN_WIDTH_MM)); + rb_define_const(mGlut, "GLUT_SCREEN_HEIGHT_MM", INT2NUM(GLUT_SCREEN_HEIGHT_MM)); + rb_define_const(mGlut, "GLUT_MENU_NUM_ITEMS", INT2NUM(GLUT_MENU_NUM_ITEMS)); + rb_define_const(mGlut, "GLUT_DISPLAY_MODE_POSSIBLE", INT2NUM(GLUT_DISPLAY_MODE_POSSIBLE)); + rb_define_const(mGlut, "GLUT_INIT_WINDOW_X", INT2NUM(GLUT_INIT_WINDOW_X)); + rb_define_const(mGlut, "GLUT_INIT_WINDOW_Y", INT2NUM(GLUT_INIT_WINDOW_Y)); + rb_define_const(mGlut, "GLUT_INIT_WINDOW_WIDTH", INT2NUM(GLUT_INIT_WINDOW_WIDTH)); + rb_define_const(mGlut, "GLUT_INIT_WINDOW_HEIGHT", INT2NUM(GLUT_INIT_WINDOW_HEIGHT)); + rb_define_const(mGlut, "GLUT_INIT_DISPLAY_MODE", INT2NUM(GLUT_INIT_DISPLAY_MODE)); + rb_define_const(mGlut, "GLUT_ELAPSED_TIME", INT2NUM(GLUT_ELAPSED_TIME)); + rb_define_const(mGlut, "GLUT_HAS_KEYBOARD", INT2NUM(GLUT_HAS_KEYBOARD)); + rb_define_const(mGlut, "GLUT_HAS_MOUSE", INT2NUM(GLUT_HAS_MOUSE)); + rb_define_const(mGlut, "GLUT_HAS_SPACEBALL", INT2NUM(GLUT_HAS_SPACEBALL)); + rb_define_const(mGlut, "GLUT_HAS_DIAL_AND_BUTTON_BOX", INT2NUM(GLUT_HAS_DIAL_AND_BUTTON_BOX)); + rb_define_const(mGlut, "GLUT_HAS_TABLET", INT2NUM(GLUT_HAS_TABLET)); + rb_define_const(mGlut, "GLUT_NUM_MOUSE_BUTTONS", INT2NUM(GLUT_NUM_MOUSE_BUTTONS)); + rb_define_const(mGlut, "GLUT_NUM_SPACEBALL_BUTTONS", INT2NUM(GLUT_NUM_SPACEBALL_BUTTONS)); + rb_define_const(mGlut, "GLUT_NUM_BUTTON_BOX_BUTTONS", INT2NUM(GLUT_NUM_BUTTON_BOX_BUTTONS)); + rb_define_const(mGlut, "GLUT_NUM_DIALS", INT2NUM(GLUT_NUM_DIALS)); + rb_define_const(mGlut, "GLUT_NUM_TABLET_BUTTONS", INT2NUM(GLUT_NUM_TABLET_BUTTONS)); + rb_define_const(mGlut, "GLUT_OVERLAY_POSSIBLE", INT2NUM(GLUT_OVERLAY_POSSIBLE)); + rb_define_const(mGlut, "GLUT_LAYER_IN_USE", INT2NUM(GLUT_LAYER_IN_USE)); + rb_define_const(mGlut, "GLUT_HAS_OVERLAY", INT2NUM(GLUT_HAS_OVERLAY)); + rb_define_const(mGlut, "GLUT_TRANSPARENT_INDEX", INT2NUM(GLUT_TRANSPARENT_INDEX)); + rb_define_const(mGlut, "GLUT_NORMAL_DAMAGED", INT2NUM(GLUT_NORMAL_DAMAGED)); + rb_define_const(mGlut, "GLUT_OVERLAY_DAMAGED", INT2NUM(GLUT_OVERLAY_DAMAGED)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_POSSIBLE", INT2NUM(GLUT_VIDEO_RESIZE_POSSIBLE)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_IN_USE", INT2NUM(GLUT_VIDEO_RESIZE_IN_USE)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_X_DELTA", INT2NUM(GLUT_VIDEO_RESIZE_X_DELTA)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_Y_DELTA", INT2NUM(GLUT_VIDEO_RESIZE_Y_DELTA)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_WIDTH_DELTA", INT2NUM(GLUT_VIDEO_RESIZE_WIDTH_DELTA)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_HEIGHT_DELTA", INT2NUM(GLUT_VIDEO_RESIZE_HEIGHT_DELTA)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_X", INT2NUM(GLUT_VIDEO_RESIZE_X)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_Y", INT2NUM(GLUT_VIDEO_RESIZE_Y)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_WIDTH", INT2NUM(GLUT_VIDEO_RESIZE_WIDTH)); + rb_define_const(mGlut, "GLUT_VIDEO_RESIZE_HEIGHT", INT2NUM(GLUT_VIDEO_RESIZE_HEIGHT)); + rb_define_const(mGlut, "GLUT_NORMAL", INT2NUM(GLUT_NORMAL)); + rb_define_const(mGlut, "GLUT_OVERLAY", INT2NUM(GLUT_OVERLAY)); + rb_define_const(mGlut, "GLUT_ACTIVE_SHIFT", INT2NUM(GLUT_ACTIVE_SHIFT)); + rb_define_const(mGlut, "GLUT_ACTIVE_CTRL", INT2NUM(GLUT_ACTIVE_CTRL)); + rb_define_const(mGlut, "GLUT_ACTIVE_ALT", INT2NUM(GLUT_ACTIVE_ALT)); + rb_define_const(mGlut, "GLUT_CURSOR_RIGHT_ARROW", INT2NUM(GLUT_CURSOR_RIGHT_ARROW)); + rb_define_const(mGlut, "GLUT_CURSOR_LEFT_ARROW", INT2NUM(GLUT_CURSOR_LEFT_ARROW)); + rb_define_const(mGlut, "GLUT_CURSOR_INFO", INT2NUM(GLUT_CURSOR_INFO)); + rb_define_const(mGlut, "GLUT_CURSOR_DESTROY", INT2NUM(GLUT_CURSOR_DESTROY)); + rb_define_const(mGlut, "GLUT_CURSOR_HELP", INT2NUM(GLUT_CURSOR_HELP)); + rb_define_const(mGlut, "GLUT_CURSOR_CYCLE", INT2NUM(GLUT_CURSOR_CYCLE)); + rb_define_const(mGlut, "GLUT_CURSOR_SPRAY", INT2NUM(GLUT_CURSOR_SPRAY)); + rb_define_const(mGlut, "GLUT_CURSOR_WAIT", INT2NUM(GLUT_CURSOR_WAIT)); + rb_define_const(mGlut, "GLUT_CURSOR_TEXT", INT2NUM(GLUT_CURSOR_TEXT)); + rb_define_const(mGlut, "GLUT_CURSOR_CROSSHAIR", INT2NUM(GLUT_CURSOR_CROSSHAIR)); + rb_define_const(mGlut, "GLUT_CURSOR_UP_DOWN", INT2NUM(GLUT_CURSOR_UP_DOWN)); + rb_define_const(mGlut, "GLUT_CURSOR_LEFT_RIGHT", INT2NUM(GLUT_CURSOR_LEFT_RIGHT)); + rb_define_const(mGlut, "GLUT_CURSOR_TOP_SIDE", INT2NUM(GLUT_CURSOR_TOP_SIDE)); + rb_define_const(mGlut, "GLUT_CURSOR_BOTTOM_SIDE", INT2NUM(GLUT_CURSOR_BOTTOM_SIDE)); + rb_define_const(mGlut, "GLUT_CURSOR_LEFT_SIDE", INT2NUM(GLUT_CURSOR_LEFT_SIDE)); + rb_define_const(mGlut, "GLUT_CURSOR_RIGHT_SIDE", INT2NUM(GLUT_CURSOR_RIGHT_SIDE)); + rb_define_const(mGlut, "GLUT_CURSOR_TOP_LEFT_CORNER", INT2NUM(GLUT_CURSOR_TOP_LEFT_CORNER)); + rb_define_const(mGlut, "GLUT_CURSOR_TOP_RIGHT_CORNER", INT2NUM(GLUT_CURSOR_TOP_RIGHT_CORNER)); + rb_define_const(mGlut, "GLUT_CURSOR_BOTTOM_RIGHT_CORNER", INT2NUM(GLUT_CURSOR_BOTTOM_RIGHT_CORNER)); + rb_define_const(mGlut, "GLUT_CURSOR_BOTTOM_LEFT_CORNER", INT2NUM(GLUT_CURSOR_BOTTOM_LEFT_CORNER)); + rb_define_const(mGlut, "GLUT_CURSOR_INHERIT", INT2NUM(GLUT_CURSOR_INHERIT)); + rb_define_const(mGlut, "GLUT_CURSOR_NONE", INT2NUM(GLUT_CURSOR_NONE)); + rb_define_const(mGlut, "GLUT_CURSOR_FULL_CROSSHAIR", INT2NUM(GLUT_CURSOR_FULL_CROSSHAIR)); + + /* hardcoded, see bitmap_font_map for explanation */ + rb_define_const(mGlut, "GLUT_BITMAP_9_BY_15", INT2NUM(0)); + rb_define_const(mGlut, "GLUT_BITMAP_8_BY_13", INT2NUM(1)); + rb_define_const(mGlut, "GLUT_BITMAP_TIMES_ROMAN_10", INT2NUM(2)); + rb_define_const(mGlut, "GLUT_BITMAP_TIMES_ROMAN_24", INT2NUM(3)); + rb_define_const(mGlut, "GLUT_BITMAP_HELVETICA_10", INT2NUM(4)); + rb_define_const(mGlut, "GLUT_BITMAP_HELVETICA_12", INT2NUM(5)); + rb_define_const(mGlut, "GLUT_BITMAP_HELVETICA_18", INT2NUM(6)); + rb_define_const(mGlut, "GLUT_STROKE_ROMAN", INT2NUM(7)); + rb_define_const(mGlut, "GLUT_STROKE_MONO_ROMAN", INT2NUM(8)); + + rb_define_const(mGlut, "GLUT_WINDOW_FORMAT_ID", INT2NUM(GLUT_WINDOW_FORMAT_ID)); + rb_define_const(mGlut, "GLUT_DEVICE_IGNORE_KEY_REPEAT", INT2NUM(GLUT_DEVICE_IGNORE_KEY_REPEAT)); + rb_define_const(mGlut, "GLUT_DEVICE_KEY_REPEAT", INT2NUM(GLUT_DEVICE_KEY_REPEAT)); + rb_define_const(mGlut, "GLUT_HAS_JOYSTICK", INT2NUM(GLUT_HAS_JOYSTICK)); + rb_define_const(mGlut, "GLUT_OWNS_JOYSTICK", INT2NUM(GLUT_OWNS_JOYSTICK)); + rb_define_const(mGlut, "GLUT_JOYSTICK_BUTTONS", INT2NUM(GLUT_JOYSTICK_BUTTONS)); + rb_define_const(mGlut, "GLUT_JOYSTICK_AXES", INT2NUM(GLUT_JOYSTICK_AXES)); + rb_define_const(mGlut, "GLUT_JOYSTICK_POLL_RATE", INT2NUM(GLUT_JOYSTICK_POLL_RATE)); + rb_define_const(mGlut, "GLUT_KEY_REPEAT_OFF", INT2NUM(GLUT_KEY_REPEAT_OFF)); + rb_define_const(mGlut, "GLUT_KEY_REPEAT_ON", INT2NUM(GLUT_KEY_REPEAT_ON)); + rb_define_const(mGlut, "GLUT_KEY_REPEAT_DEFAULT", INT2NUM(GLUT_KEY_REPEAT_DEFAULT)); + rb_define_const(mGlut, "GLUT_JOYSTICK_BUTTON_A", INT2NUM(GLUT_JOYSTICK_BUTTON_A)); + rb_define_const(mGlut, "GLUT_JOYSTICK_BUTTON_B", INT2NUM(GLUT_JOYSTICK_BUTTON_B)); + rb_define_const(mGlut, "GLUT_JOYSTICK_BUTTON_C", INT2NUM(GLUT_JOYSTICK_BUTTON_C)); + rb_define_const(mGlut, "GLUT_JOYSTICK_BUTTON_D", INT2NUM(GLUT_JOYSTICK_BUTTON_D)); + rb_define_const(mGlut, "GLUT_GAME_MODE_ACTIVE", INT2NUM(GLUT_GAME_MODE_ACTIVE)); + rb_define_const(mGlut, "GLUT_GAME_MODE_POSSIBLE", INT2NUM(GLUT_GAME_MODE_POSSIBLE)); + rb_define_const(mGlut, "GLUT_GAME_MODE_WIDTH", INT2NUM(GLUT_GAME_MODE_WIDTH)); + rb_define_const(mGlut, "GLUT_GAME_MODE_HEIGHT", INT2NUM(GLUT_GAME_MODE_HEIGHT)); + rb_define_const(mGlut, "GLUT_GAME_MODE_PIXEL_DEPTH", INT2NUM(GLUT_GAME_MODE_PIXEL_DEPTH)); + rb_define_const(mGlut, "GLUT_GAME_MODE_REFRESH_RATE", INT2NUM(GLUT_GAME_MODE_REFRESH_RATE)); + rb_define_const(mGlut, "GLUT_GAME_MODE_DISPLAY_CHANGED", INT2NUM(GLUT_GAME_MODE_DISPLAY_CHANGED)); + + // Some OSX specific constants +#ifdef GLUT_NO_RECOVERY + rb_define_const(mGlut, "GLUT_NO_RECOVERY", INT2NUM(GLUT_NO_RECOVERY)); +#endif +#ifdef GLUT_3_2_CORE_PROFILE + rb_define_const(mGlut, "GLUT_3_2_CORE_PROFILE", INT2NUM(GLUT_3_2_CORE_PROFILE)); +#endif + + Init_glut_callbacks(); + Init_glut_ext(); +} diff --git a/ext/glut/glut_callbacks.c b/ext/glut/glut_callbacks.c new file mode 100644 index 0000000..5ad16bc --- /dev/null +++ b/ext/glut/glut_callbacks.c @@ -0,0 +1,845 @@ +#include "common.h" + +/* HACK experimental API */ +void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1); + +static ID call_id; /* 'call' method id */ +static VALUE idle_func = Qnil; +static VALUE joystick_func = Qnil; +static VALUE menustate_func = Qnil; +static VALUE menustatus_func = Qnil; +static VALUE timer_func = Qnil; + +typedef void *(*gvl_call)(void *); + +struct callback_args { + union { + int button; + int dial; + int special; + int state; + int value; + int width; + int x; + unsigned char key; + unsigned int button_mask; + } arg0; + union { + int height; + int state; + int value; + int x; + int y; + } arg1; + union { + int x; + int y; + int z; + } arg2; + union { + int y; + int z; + } arg3; +} ; + +static struct callback_args * +alloc_callback_args(void) { + struct callback_args *args; + args = (struct callback_args *)malloc(sizeof(struct callback_args)); + + if (args == NULL) { + fprintf(stderr, "[BUG] out of memory in opengl callback"); + abort(); + } + + return args; +} + +/* + * macros for registering callbacks - + * + * most GLUT callback functions are part of specific window state, so + * the same callback may have different functions for each GLUT window + * + * callbacks that are not tied to specific window (idle,timer,menustate) are + * registered manually + */ + +#define WINDOW_CALLBACK_SETUP(_funcname) \ +static VALUE _funcname = Qnil; \ +static VALUE \ +glut_ ## _funcname(VALUE self, VALUE callback) \ +{ \ + int win = glutGetWindow(); \ + \ + if (win == 0) { \ + rb_raise(rb_eRuntimeError, "glut%s needs current window", #_funcname); \ + } \ + \ + callback = rb_glut_check_callback(self, callback); \ + \ + rb_ary_store(_funcname, win, callback); \ + \ + if (NIL_P(callback)) \ + glut##_funcname(NULL); \ + else \ + glut##_funcname(&glut_##_funcname##Callback0); \ + \ + return Qnil; \ +} + +#define WINDOW_CALLBACK_DEFINE(module, _funcname) \ + rb_define_module_function(module, "glut"#_funcname, glut_##_funcname, 1); \ + rb_global_variable(&_funcname); \ + _funcname = rb_ary_new() + +static void GLUTCALLBACK glut_DisplayFuncCallback0(void); +static void GLUTCALLBACK glut_ReshapeFuncCallback0(int, int); +static void GLUTCALLBACK glut_KeyboardFuncCallback0(unsigned char, int, int); +static void GLUTCALLBACK glut_MouseFuncCallback0(int, int, int, int); +static void GLUTCALLBACK glut_MotionFuncCallback0(int, int); +static void GLUTCALLBACK glut_PassiveMotionFuncCallback0(int, int); +static void GLUTCALLBACK glut_EntryFuncCallback0(int); +static void GLUTCALLBACK glut_VisibilityFuncCallback0(int); +static void GLUTCALLBACK glut_SpecialFuncCallback0(int, int, int); +static void GLUTCALLBACK glut_SpaceballMotionFuncCallback0(int, int, int); +static void GLUTCALLBACK glut_SpaceballRotateFuncCallback0(int, int, int); +static void GLUTCALLBACK glut_SpaceballButtonFuncCallback0(int, int); +static void GLUTCALLBACK glut_ButtonBoxFuncCallback0(int, int); +static void GLUTCALLBACK glut_DialsFuncCallback0(int, int); +static void GLUTCALLBACK glut_TabletMotionFuncCallback0(int, int); +static void GLUTCALLBACK glut_TabletButtonFuncCallback0(int, int, int, int); +static void GLUTCALLBACK glut_OverlayDisplayFuncCallback0(void); +static void GLUTCALLBACK glut_WindowStatusFuncCallback0(int); +static void GLUTCALLBACK glut_JoystickFuncCallback0(unsigned int, int, int, int); +static void GLUTCALLBACK glut_KeyboardUpFuncCallback0(unsigned char, int, int); +static void GLUTCALLBACK glut_SpecialUpFuncCallback0(int, int, int); + +WINDOW_CALLBACK_SETUP(DisplayFunc) +WINDOW_CALLBACK_SETUP(ReshapeFunc) +WINDOW_CALLBACK_SETUP(KeyboardFunc) +WINDOW_CALLBACK_SETUP(MouseFunc) +WINDOW_CALLBACK_SETUP(MotionFunc) +WINDOW_CALLBACK_SETUP(PassiveMotionFunc) +WINDOW_CALLBACK_SETUP(EntryFunc) +WINDOW_CALLBACK_SETUP(VisibilityFunc) +WINDOW_CALLBACK_SETUP(SpecialFunc) +WINDOW_CALLBACK_SETUP(SpaceballMotionFunc) +WINDOW_CALLBACK_SETUP(SpaceballRotateFunc) +WINDOW_CALLBACK_SETUP(SpaceballButtonFunc) +WINDOW_CALLBACK_SETUP(ButtonBoxFunc) +WINDOW_CALLBACK_SETUP(DialsFunc) +WINDOW_CALLBACK_SETUP(TabletMotionFunc) +WINDOW_CALLBACK_SETUP(TabletButtonFunc) +WINDOW_CALLBACK_SETUP(OverlayDisplayFunc) +WINDOW_CALLBACK_SETUP(WindowStatusFunc) +WINDOW_CALLBACK_SETUP(KeyboardUpFunc) +WINDOW_CALLBACK_SETUP(SpecialUpFunc) + +GLUT_SIMPLE_FUNCTION(ForceJoystickFunc) + +static void * +glut_DisplayFuncCallback(void *ignored) { + VALUE func; + + func = rb_ary_entry(DisplayFunc, glutGetWindow()); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 0); + + return NULL; +} + +static void GLUTCALLBACK +glut_DisplayFuncCallback0(void) { + rb_thread_call_with_gvl(glut_DisplayFuncCallback, NULL); +} + +static void * +glut_ReshapeFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(ReshapeFunc, glutGetWindow()); + VALUE width = INT2FIX(args->arg0.width); + VALUE height = INT2FIX(args->arg1.height); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 2, width, height); + + return NULL; +} + +static void GLUTCALLBACK +glut_ReshapeFuncCallback0(int width, int height) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.width = width; + args->arg1.height = height; + + rb_thread_call_with_gvl((gvl_call)glut_ReshapeFuncCallback, args); + + free(args); +} + +static void * +glut_KeyboardFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(KeyboardFunc, glutGetWindow()); +#if HAVE_SINGLE_BYTE_STRINGS + VALUE key = rb_str_new((char *)&args->arg0.key, 1); +#else + VALUE key = UINT2NUM((unsigned char)args->arg0.key); +#endif + VALUE x = INT2FIX(args->arg1.x); + VALUE y = INT2FIX(args->arg2.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 3, key, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_KeyboardFuncCallback0(unsigned char key, int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.key = key; + args->arg1.x = x; + args->arg2.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_KeyboardFuncCallback, args); + + free(args); +} + +static void * +glut_KeyboardUpFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(KeyboardUpFunc, glutGetWindow()); +#if HAVE_SINGLE_BYTE_STRINGS + VALUE key = rb_str_new((char *)&args->arg0.key, 1); +#else + VALUE key = UINT2NUM((unsigned char)args->arg0.key); +#endif + VALUE x = INT2FIX(args->arg1.x); + VALUE y = INT2FIX(args->arg2.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 3, key, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_KeyboardUpFuncCallback0(unsigned char key, int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.key = key; + args->arg1.x = x; + args->arg2.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_KeyboardUpFuncCallback, args); + + free(args); +} + +static void * +glut_MouseFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(MouseFunc, glutGetWindow()); + + VALUE button = INT2FIX(args->arg0.button); + VALUE state = INT2FIX(args->arg1.state); + VALUE x = INT2FIX(args->arg2.x); + VALUE y = INT2FIX(args->arg3.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 4, button, state, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_MouseFuncCallback0(int button, int state, int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.button = button; + args->arg1.state = state; + args->arg2.x = x; + args->arg3.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_MouseFuncCallback, args); + + free(args); +} + +static void * +glut_MotionFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(MotionFunc, glutGetWindow()); + VALUE x = INT2FIX(args->arg0.x); + VALUE y = INT2FIX(args->arg1.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 2, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_MotionFuncCallback0(int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.x = x; + args->arg1.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_MotionFuncCallback, args); + + free(args); +} + +static void * +glut_PassiveMotionFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(PassiveMotionFunc, glutGetWindow()); + VALUE x = INT2FIX(args->arg0.x); + VALUE y = INT2FIX(args->arg1.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 2, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_PassiveMotionFuncCallback0(int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.x = x; + args->arg1.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_PassiveMotionFuncCallback, args); + + free(args); +} + +static void * +glut_EntryFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(EntryFunc, glutGetWindow()); + VALUE state = INT2NUM(args->arg0.state); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 1, state); + + return NULL; +} + +static void GLUTCALLBACK +glut_EntryFuncCallback0(int state) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.state = state; + + rb_thread_call_with_gvl((gvl_call)glut_EntryFuncCallback, args); + + free(args); +} + +static void * +glut_VisibilityFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(VisibilityFunc, glutGetWindow()); + VALUE state = INT2NUM(args->arg0.state); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 1, state); + + return NULL; +} + +static void GLUTCALLBACK +glut_VisibilityFuncCallback0(int state) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.state = state; + + rb_thread_call_with_gvl((gvl_call)glut_VisibilityFuncCallback, args); + + free(args); +} + +static void * +glut_IdleFuncCallback(void *ignored) { + if (!NIL_P(idle_func)) + rb_funcall(idle_func, call_id, 0); + + return NULL; +} + +static void GLUTCALLBACK +glut_IdleFuncCallback0(void) { + rb_thread_call_with_gvl((gvl_call)glut_IdleFuncCallback, NULL); +} + +static void * +glut_TimerFuncCallback(struct callback_args *args) { + VALUE value = INT2NUM(args->arg0.value); + + if (!NIL_P(timer_func)) + rb_funcall(timer_func, call_id, 1, value); + + return NULL; +} + +static void GLUTCALLBACK +glut_TimerFuncCallback0(int value) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.value = value; + + rb_thread_call_with_gvl((gvl_call)glut_TimerFuncCallback, args); + + free(args); +} + +static void * +glut_MenuStateFuncCallback(struct callback_args *args) { + VALUE state = INT2NUM(args->arg0.state); + + if (!NIL_P(menustate_func)) + rb_funcall(menustate_func, call_id, 1, state); + + return NULL; +} + +static void GLUTCALLBACK +glut_MenuStateFuncCallback0(int state) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.state = state; + + rb_thread_call_with_gvl((gvl_call)glut_MenuStateFuncCallback, args); + + free(args); +} + +static void * +glut_MenuStatusFuncCallback(struct callback_args *args) { + VALUE state = INT2NUM(args->arg0.state); + VALUE x = INT2NUM(args->arg1.x); + VALUE y = INT2NUM(args->arg2.y); + + if (!NIL_P(menustatus_func)) + rb_funcall(menustatus_func, call_id, 3, state, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_MenuStatusFuncCallback0(int state, int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.state = state; + args->arg1.x = x; + args->arg2.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_MenuStatusFuncCallback, args); + + free(args); +} + +static void * +glut_SpecialFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(SpecialFunc, glutGetWindow()); + VALUE key = INT2NUM(args->arg0.key); + VALUE x = INT2NUM(args->arg1.x); + VALUE y = INT2NUM(args->arg2.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 3, key, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_SpecialFuncCallback0(int key, int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.key = key; + args->arg1.x = x; + args->arg2.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_SpecialFuncCallback, args); + + free(args); +} + +static void * +glut_SpecialUpFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(SpecialUpFunc, glutGetWindow()); + VALUE key = INT2NUM(args->arg0.key); + VALUE x = INT2NUM(args->arg1.x); + VALUE y = INT2NUM(args->arg2.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 3, key, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_SpecialUpFuncCallback0(int key, int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.key = key; + args->arg1.x = x; + args->arg2.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_SpecialUpFuncCallback, args); + + free(args); +} + +static void * +glut_SpaceballMotionFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(SpaceballMotionFunc, glutGetWindow()); + VALUE x = INT2NUM(args->arg0.x); + VALUE y = INT2NUM(args->arg1.y); + VALUE z = INT2NUM(args->arg2.z); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 3, x, y, z); + + return NULL; +} + +static void GLUTCALLBACK +glut_SpaceballMotionFuncCallback0(int x, int y, int z) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.x = x; + args->arg1.y = y; + args->arg2.z = z; + + rb_thread_call_with_gvl((gvl_call)glut_SpaceballMotionFuncCallback, args); + + free(args); +} + +static void * +glut_SpaceballRotateFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(SpaceballRotateFunc, glutGetWindow()); + VALUE x = INT2NUM(args->arg0.x); + VALUE y = INT2NUM(args->arg1.y); + VALUE z = INT2NUM(args->arg2.z); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 3, x, y, z); + + return NULL; +} + +static void GLUTCALLBACK +glut_SpaceballRotateFuncCallback0(int x, int y, int z) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.x = x; + args->arg1.y = y; + args->arg2.z = z; + + rb_thread_call_with_gvl((gvl_call)glut_SpaceballRotateFuncCallback, args); + + free(args); +} + +static void * +glut_SpaceballButtonFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(SpaceballButtonFunc, glutGetWindow()); + VALUE button = INT2NUM(args->arg0.button); + VALUE state = INT2NUM(args->arg1.state); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 2, button, state); + + return NULL; +} + +static void GLUTCALLBACK +glut_SpaceballButtonFuncCallback0(int button, int state) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.button = button; + args->arg1.state = state; + + rb_thread_call_with_gvl((gvl_call)glut_SpaceballButtonFuncCallback, args); + + free(args); +} + +static void * +glut_ButtonBoxFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(ButtonBoxFunc, glutGetWindow()); + VALUE button = INT2NUM(args->arg0.button); + VALUE state = INT2NUM(args->arg1.state); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 2, button, state); + + return NULL; +} + +static void GLUTCALLBACK +glut_ButtonBoxFuncCallback0(int button, int state) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.button = button; + args->arg1.state = state; + + rb_thread_call_with_gvl((gvl_call)glut_ButtonBoxFuncCallback, args); + + free(args); +} + +static void * +glut_DialsFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(DialsFunc, glutGetWindow()); + VALUE dial = INT2NUM(args->arg0.dial); + VALUE value = INT2NUM(args->arg1.value); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 2, dial, value); + + return NULL; +} + +static void GLUTCALLBACK +glut_DialsFuncCallback0(int dial, int value) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.dial = dial; + args->arg1.value = value; + + rb_thread_call_with_gvl((gvl_call)glut_DialsFuncCallback, args); + + free(args); +} + +static void * +glut_TabletMotionFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(TabletMotionFunc, glutGetWindow()); + VALUE x = INT2NUM(args->arg0.x); + VALUE y = INT2NUM(args->arg1.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 2, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_TabletMotionFuncCallback0(int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.x = x; + args->arg1.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_TabletMotionFuncCallback, args); + + free(args); +} + +static void * +glut_TabletButtonFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(TabletButtonFunc, glutGetWindow()); + VALUE button = INT2NUM(args->arg0.button); + VALUE state = INT2NUM(args->arg1.state); + VALUE x = INT2NUM(args->arg2.x); + VALUE y = INT2NUM(args->arg3.y); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 4, button, state, x, y); + + return NULL; +} + +static void GLUTCALLBACK +glut_TabletButtonFuncCallback0(int button, int state, int x, int y) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.button = button; + args->arg1.state = state; + args->arg2.x = x; + args->arg3.y = y; + + rb_thread_call_with_gvl((gvl_call)glut_TabletButtonFuncCallback, args); + + free(args); +} + +static void * +glut_OverlayDisplayFuncCallback(void) { + VALUE func = rb_ary_entry(OverlayDisplayFunc, glutGetWindow()); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 0); + + return NULL; +} + +static void GLUTCALLBACK +glut_OverlayDisplayFuncCallback0(void) { + rb_thread_call_with_gvl((gvl_call)glut_OverlayDisplayFuncCallback, NULL); +} + +static void * +glut_WindowStatusFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(WindowStatusFunc, glutGetWindow()); + VALUE state = INT2NUM(args->arg0.state); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 1, state); + + return NULL; +} + +static void GLUTCALLBACK +glut_WindowStatusFuncCallback0(int state) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.state = state; + + rb_thread_call_with_gvl((gvl_call)glut_WindowStatusFuncCallback, args); + + free(args); +} + +static void * +glut_JoystickFuncCallback(struct callback_args *args) { + VALUE func = rb_ary_entry(joystick_func, glutGetWindow()); + VALUE button_mask = UINT2NUM(args->arg0.button_mask); + VALUE x = INT2NUM(args->arg1.x); + VALUE y = INT2NUM(args->arg2.y); + VALUE z = INT2NUM(args->arg3.z); + + if (!NIL_P(func)) + rb_funcall(func, call_id, 4, button_mask, x, y, z); + + return NULL; +} + +static void GLUTCALLBACK +glut_JoystickFuncCallback0(unsigned int button_mask, int x, int y, int z) { + struct callback_args *args = alloc_callback_args(); + + args->arg0.button_mask = button_mask; + args->arg1.x = x; + args->arg2.y = y; + args->arg3.z = z; + + rb_thread_call_with_gvl((gvl_call)glut_JoystickFuncCallback, args); + + free(args); +} + +static VALUE +glut_JoystickFunc(VALUE self, VALUE callback, VALUE _poll_interval) { + int win = glutGetWindow(); + int poll_interval = NUM2INT(_poll_interval); + + if (win == 0) + rb_raise(rb_eRuntimeError, "glutJoystickFunc needs current window"); + + callback = rb_glut_check_callback(self, callback); + + rb_ary_store(joystick_func, win, callback); + + if (NIL_P(callback)) + glutJoystickFunc(NULL, -1); + else + glutJoystickFunc(glut_JoystickFuncCallback0, poll_interval); + + return Qnil; +} + +static VALUE +glut_IdleFunc(VALUE self, VALUE callback) { + callback = rb_glut_check_callback(self, callback); + + idle_func = callback; + + if (NIL_P(callback)) + glutIdleFunc(NULL); + else + glutIdleFunc(glut_IdleFuncCallback0); + + return Qnil; +} + +static VALUE +glut_MenuStateFunc(VALUE self, VALUE callback) { + menustate_func = rb_glut_check_callback(self, callback); + + if (NIL_P(menustate_func)) + glutMenuStateFunc(NULL); + else + glutMenuStateFunc(glut_MenuStateFuncCallback0); + + return Qnil; +} + +static VALUE +glut_MenuStatusFunc(VALUE self, VALUE callback) { + menustatus_func = rb_glut_check_callback(self, callback); + + if (NIL_P(menustatus_func)) + glutMenuStatusFunc(NULL); + else + glutMenuStatusFunc(glut_MenuStatusFuncCallback0); + + return Qnil; +} + +static VALUE +glut_TimerFunc(VALUE self, VALUE _msec, VALUE callback, VALUE _value) { + unsigned int msec = NUM2UINT(_msec); + int value = NUM2INT(_value); + + timer_func = rb_glut_check_callback(self, callback); + + glutTimerFunc(msec, glut_TimerFuncCallback0, value); + + return Qnil; +} + +void Init_glut_callbacks() { + VALUE mGlut = rb_path2class("Glut"); + + call_id = rb_intern("call"); + joystick_func = rb_ary_new(); + + rb_global_variable(&joystick_func); + rb_gc_register_address(&idle_func); + rb_gc_register_address(&timer_func); + rb_gc_register_address(&menustate_func); + + rb_define_module_function(mGlut, "glutJoystickFunc", glut_JoystickFunc, 2); + rb_define_module_function(mGlut, "glutForceJoystickFunc", glut_ForceJoystickFunc, 0); + rb_define_module_function(mGlut, "glutIdleFunc", glut_IdleFunc, 1); + rb_define_module_function(mGlut, "glutMenuStateFunc", glut_MenuStateFunc, 1); + rb_define_module_function(mGlut, "glutMenuStatusFunc", glut_MenuStatusFunc, 1); + rb_define_module_function(mGlut, "glutTimerFunc", glut_TimerFunc, 3); + + WINDOW_CALLBACK_DEFINE(mGlut, ButtonBoxFunc); + WINDOW_CALLBACK_DEFINE(mGlut, DialsFunc); + WINDOW_CALLBACK_DEFINE(mGlut, DisplayFunc); + WINDOW_CALLBACK_DEFINE(mGlut, EntryFunc); + WINDOW_CALLBACK_DEFINE(mGlut, KeyboardFunc); + WINDOW_CALLBACK_DEFINE(mGlut, KeyboardUpFunc); + WINDOW_CALLBACK_DEFINE(mGlut, MotionFunc); + WINDOW_CALLBACK_DEFINE(mGlut, MouseFunc); + WINDOW_CALLBACK_DEFINE(mGlut, OverlayDisplayFunc); + WINDOW_CALLBACK_DEFINE(mGlut, PassiveMotionFunc); + WINDOW_CALLBACK_DEFINE(mGlut, ReshapeFunc); + WINDOW_CALLBACK_DEFINE(mGlut, SpaceballButtonFunc); + WINDOW_CALLBACK_DEFINE(mGlut, SpaceballMotionFunc); + WINDOW_CALLBACK_DEFINE(mGlut, SpaceballRotateFunc); + WINDOW_CALLBACK_DEFINE(mGlut, SpecialFunc); + WINDOW_CALLBACK_DEFINE(mGlut, SpecialUpFunc); + WINDOW_CALLBACK_DEFINE(mGlut, TabletButtonFunc); + WINDOW_CALLBACK_DEFINE(mGlut, TabletMotionFunc); + WINDOW_CALLBACK_DEFINE(mGlut, VisibilityFunc); + WINDOW_CALLBACK_DEFINE(mGlut, WindowStatusFunc); +} + diff --git a/ext/glut/glut_ext.c b/ext/glut/glut_ext.c new file mode 100644 index 0000000..8f865b1 --- /dev/null +++ b/ext/glut/glut_ext.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2013 Blaž Hrastnik + * + * This program is distributed under the terms of the MIT license. + * See the included COPYRIGHT file for the terms of this license. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common.h" + +/* + * Process loop function, see freeglut_main.c + */ +GLUT_SIMPLE_FUNCTION(MainLoopEvent) +GLUT_SIMPLE_FUNCTION(LeaveMainLoop) +GLUT_SIMPLE_FUNCTION(Exit) + +/* + * Window management functions, see freeglut_window.c + */ +GLUT_SIMPLE_FUNCTION(FullScreenToggle) +GLUT_SIMPLE_FUNCTION(LeaveFullScreen) + +/* Initialization functions */ +static VALUE +glut_InitContextVersion(VALUE obj, VALUE majorVersion, VALUE minorVersion) +{ + glutInitContextVersion(NUM2INT(majorVersion), NUM2INT(minorVersion)); + return Qnil; +} + +static VALUE +glut_InitContextFlags(VALUE obj, VALUE flags) +{ + glutInitContextFlags(NUM2INT(flags)); + return Qnil; +} + +static VALUE +glut_InitContextProfile(VALUE obj, VALUE profile) +{ + glutInitContextProfile(NUM2INT(profile)); + return Qnil; +} + +void Init_glut_ext() { + VALUE mGlut = rb_path2class("Glut"); + + /* Process loop functions */ + rb_define_module_function(mGlut, "glutMainLoopEvent", glut_MainLoopEvent, 0); + rb_define_module_function(mGlut, "glutLeaveMainLoop", glut_LeaveMainLoop, 0); + rb_define_module_function(mGlut, "glutExit", glut_Exit, 0); + + /* Window management functions */ + rb_define_module_function(mGlut, "glutFullScreenToggle", glut_FullScreenToggle, 0); + rb_define_module_function(mGlut, "glutLeaveFullScreen", glut_LeaveFullScreen, 0); + + /* Initialization functions */ + rb_define_module_function(mGlut, "glutInitContextVersion", glut_InitContextVersion, 2); + rb_define_module_function(mGlut, "glutInitContextFlags", glut_InitContextFlags, 1); + rb_define_module_function(mGlut, "glutInitContextProfile", glut_InitContextProfile, 1); + + /* Context-related flags */ +#ifdef GLUT_INIT_MAJOR_VERSION + rb_define_const(mGlut, "GLUT_INIT_MAJOR_VERSION", INT2NUM(GLUT_INIT_MAJOR_VERSION)); +#endif +#ifdef GLUT_INIT_MINOR_VERSION + rb_define_const(mGlut, "GLUT_INIT_MINOR_VERSION", INT2NUM(GLUT_INIT_MINOR_VERSION)); +#endif +#ifdef GLUT_INIT_FLAGS + rb_define_const(mGlut, "GLUT_INIT_FLAGS", INT2NUM(GLUT_INIT_FLAGS)); +#endif +#ifdef GLUT_INIT_PROFILE + rb_define_const(mGlut, "GLUT_INIT_PROFILE", INT2NUM(GLUT_INIT_PROFILE)); +#endif + + /* Flags for glutInitContextFlags */ +#ifdef GLUT_FORWARD_COMPATIBLE + rb_define_const(mGlut, "GLUT_FORWARD_COMPATIBLE", INT2NUM(GLUT_FORWARD_COMPATIBLE)); +#endif +#ifdef GLUT_DEBUG + rb_define_const(mGlut, "GLUT_DEBUG", INT2NUM(GLUT_DEBUG)); +#endif + + /* Flags for glutInitContextProfile */ +#ifdef GLUT_CORE_PROFILE + rb_define_const(mGlut, "GLUT_CORE_PROFILE", INT2NUM(GLUT_CORE_PROFILE)); +#endif +#ifdef GLUT_COMPATIBILITY_PROFILE + rb_define_const(mGlut, "GLUT_COMPATIBILITY_PROFILE", INT2NUM(GLUT_COMPATIBILITY_PROFILE)); +#endif +} diff --git a/glut.gemspec b/glut.gemspec new file mode 100644 index 0000000..127c01e --- /dev/null +++ b/glut.gemspec @@ -0,0 +1,50 @@ +######################################################### +# This file has been automatically generated by gem2tgz # +######################################################### +# -*- encoding: utf-8 -*- +# stub: glut 8.3.0 ruby lib +# stub: ext/glut/extconf.rb + +Gem::Specification.new do |s| + s.name = "glut".freeze + s.version = "8.3.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Eric Hodel".freeze, "Lars Kanis".freeze, "Bla\u017E Hrastnik".freeze, "Alain Hoang".freeze, "Jan Dvorak".freeze, "Minh Thu Vo".freeze, "James Adam".freeze] + s.date = "2017-06-02" + s.description = "Glut bindings for OpenGL. To be used with the {opengl}[https://github.com/larskanis/opengl] gem.".freeze + s.email = ["drbrain@segment7.net".freeze, "lars@greiz-reinsdorf.de".freeze, "speed.the.bboy@gmail.com".freeze, "".freeze, "".freeze, "".freeze, "".freeze] + s.extensions = ["ext/glut/extconf.rb".freeze] + s.extra_rdoc_files = ["History.rdoc".freeze, "Manifest.txt".freeze, "README.rdoc".freeze] + s.files = [".autotest".freeze, ".gemtest".freeze, ".gitignore".freeze, ".travis.yml".freeze, "History.rdoc".freeze, "MIT-LICENSE".freeze, "Manifest.txt".freeze, "README.rdoc".freeze, "Rakefile".freeze, "ext/glut/common.h".freeze, "ext/glut/extconf.rb".freeze, "ext/glut/glut.c".freeze, "ext/glut/glut_callbacks.c".freeze, "ext/glut/glut_ext.c".freeze, "lib/glut.rb".freeze, "lib/glut/dummy.rb".freeze] + s.licenses = ["MIT".freeze] + s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] + s.required_ruby_version = Gem::Requirement.new(">= 1.9.2".freeze) + s.rubygems_version = "2.7.6.2".freeze + s.summary = "Glut bindings for OpenGL".freeze + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q.freeze, ["~> 3.16"]) + s.add_development_dependency(%q.freeze, ["~> 2.1"]) + s.add_development_dependency(%q.freeze, ["~> 1.0"]) + s.add_development_dependency(%q.freeze, ["~> 0.6.0"]) + s.add_development_dependency(%q.freeze, ["~> 4.0"]) + else + s.add_dependency(%q.freeze, ["~> 3.16"]) + s.add_dependency(%q.freeze, ["~> 2.1"]) + s.add_dependency(%q.freeze, ["~> 1.0"]) + s.add_dependency(%q.freeze, ["~> 0.6.0"]) + s.add_dependency(%q.freeze, ["~> 4.0"]) + end + else + s.add_dependency(%q.freeze, ["~> 3.16"]) + s.add_dependency(%q.freeze, ["~> 2.1"]) + s.add_dependency(%q.freeze, ["~> 1.0"]) + s.add_dependency(%q.freeze, ["~> 0.6.0"]) + s.add_dependency(%q.freeze, ["~> 4.0"]) + end +end diff --git a/lib/glut/dummy.rb b/lib/glut/dummy.rb new file mode 100644 index 0000000..8231ff7 --- /dev/null +++ b/lib/glut/dummy.rb @@ -0,0 +1,2 @@ +# Unless this file exists, rake-compiler/hoe won't create this folder +# and the extension won't build. \ No newline at end of file diff --git a/lib/glut.rb b/lib/glut.rb new file mode 100644 index 0000000..95d0d7b --- /dev/null +++ b/lib/glut.rb @@ -0,0 +1,29 @@ +begin + RUBY_VERSION =~ /(\d+.\d+)/ + require "glut/#{$1}/glut" +rescue LoadError + require 'glut/glut' +end + +# (Glut.)glutInit -> GLUT.Init +# (Glut::)GLUT_RGBA -> GLUT::RGBA +module GLUT + extend self + include Glut + + Glut.constants.each do |cn| + n = cn.to_s.sub(/^GLUT_/,'') + next if n =~ /^[0-9]/ + const_set( n, Glut.const_get( cn ) ) + end + + Glut.methods( false ).each do |mn| + n = mn.to_s.sub(/^glut/,'') + alias_method( n, mn ) + public( n ) + end +end + +module Glut + VERSION = "8.3.0" +end