ruby-sdl2 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ require 'sdl2_ext'
2
+ require 'sdl2/version'
3
+
@@ -0,0 +1,6 @@
1
+ module SDL2
2
+ # Version string of Ruby/SDL2
3
+ VERSION = "0.1.0"
4
+ # Version of Ruby/SDL2, [major, minor, patch level]
5
+ VERSION_NUMBER = [0, 1, 0]
6
+ end
data/main.c ADDED
@@ -0,0 +1,244 @@
1
+ #define SDL2_EXTERN
2
+ #include "rubysdl2_internal.h"
3
+ #include <SDL.h>
4
+ #include <SDL_version.h>
5
+ #include <stdio.h>
6
+ #ifdef HAVE_SDL_IMAGE_H
7
+ #include <SDL_image.h>
8
+ #endif
9
+ #ifdef HAVE_SDL_MIXER_H
10
+ #include <SDL_mixer.h>
11
+ #endif
12
+ #ifdef HAVE_SDL_TTF_H
13
+ #include <SDL_ttf.h>
14
+ #endif
15
+ #include <stdarg.h>
16
+ #include <ruby/encoding.h>
17
+
18
+ int rubysdl2_handle_error(int code, const char* cfunc)
19
+ {
20
+ VALUE err;
21
+ char err_msg[1024];
22
+
23
+ if (code >= 0)
24
+ return code;
25
+
26
+ snprintf(err_msg, sizeof(err_msg), "%s (cfunc=%s)", SDL_GetError(), cfunc);
27
+ err = rb_exc_new2(eSDL2Error, err_msg);
28
+ rb_iv_set(eSDL2Error, "@error_code", INT2NUM(code));
29
+
30
+ rb_exc_raise(err);
31
+ }
32
+
33
+ void rubysdl2_define_attr_readers(VALUE klass, ...)
34
+ {
35
+ va_list ap;
36
+
37
+ va_start(ap, klass);
38
+ for (;;) {
39
+ const char* field_name = va_arg(ap, const char*);
40
+ if (field_name == NULL)
41
+ break;
42
+ rb_define_attr(klass, field_name, 1, 0);
43
+ }
44
+ va_end(ap);
45
+ }
46
+
47
+ VALUE utf8str_new_cstr(const char* str)
48
+ {
49
+ return rb_enc_str_new(str, strlen(str), rb_utf8_encoding());
50
+ }
51
+
52
+ VALUE SDL_version_to_String(const SDL_version* ver)
53
+ {
54
+ return rb_sprintf("%d.%d.%d", ver->major, ver->minor, ver->patch);
55
+ }
56
+
57
+ VALUE SDL_version_to_Array(const SDL_version* ver)
58
+ {
59
+ return rb_ary_new3(3, INT2FIX(ver->major), INT2FIX(ver->minor), INT2FIX(ver->patch));
60
+ }
61
+
62
+ const char* INT2BOOLCSTR(int n)
63
+ {
64
+ return n ? "true" : "false";
65
+ }
66
+
67
+ typedef enum {
68
+ NOT_INITIALIZED, INITIALIZDED, FINALIZED
69
+ } sdl2_state;
70
+
71
+ static sdl2_state state = NOT_INITIALIZED;
72
+
73
+ static void quit(VALUE unused)
74
+ {
75
+ if (state != INITIALIZDED)
76
+ return;
77
+
78
+ #ifdef HAVE_SDL_IMAGE_H
79
+ IMG_Quit();
80
+ #endif
81
+ #ifdef HAVE_SDL_MIXER_H
82
+ Mix_Quit();
83
+ #endif
84
+ #ifdef HAVE_SDL_TTF_H
85
+ TTF_Quit();
86
+ #endif
87
+ SDL_VideoQuit();
88
+ SDL_Quit();
89
+ state = FINALIZED;
90
+ }
91
+
92
+ /*
93
+ * Initialize SDL.
94
+ * You must call this function before using any other Ruby/SDL2 methods.
95
+ *
96
+ * You can specify initialized subsystem by flags which is
97
+ * bitwise OR of the following constants:
98
+ *
99
+ * * SDL2::INIT_TIMER - timer subsystem
100
+ * * SDL2::INIT_AUDIO - audio subsystem
101
+ * * SDL2::INIT_VIDEO - video subsystem
102
+ * * SDL2::INIT_JOYSTICK - joystick subsystem
103
+ * * SDL2::INIT_HAPTIC - haptic (force feedback) subsystem
104
+ * (interface is not implemented yet)
105
+ * * SDL2::INIT_GAMECONTROLLER - controller subsystem
106
+ * * SDL2::INIT_EVENTS - events subsystem
107
+ * * SDL2::INIT_EVERYTHING - all of the above flags
108
+ * * SDL2::INIT_NOPARACHUTE - this flag is ignored; for compatibility
109
+ *
110
+ * @overload init(flags)
111
+ *
112
+ * @param [Integer] flags initializing subsystems
113
+ *
114
+ * @return [nil]
115
+ */
116
+ static VALUE SDL2_s_init(VALUE self, VALUE flags)
117
+ {
118
+ SDL_SetMainReady();
119
+ HANDLE_ERROR(SDL_Init(NUM2UINT(flags)));
120
+ state = INITIALIZDED;
121
+ return Qnil;
122
+ }
123
+
124
+ int rubysdl2_is_active(void)
125
+ {
126
+ return state == INITIALIZDED;
127
+ }
128
+
129
+ static VALUE libsdl_version(void)
130
+ {
131
+ SDL_version version;
132
+ SDL_GetVersion(&version);
133
+ return SDL_version_to_String(&version);
134
+ }
135
+
136
+ static VALUE libsdl_version_number(void)
137
+ {
138
+ SDL_version version;
139
+ SDL_GetVersion(&version);
140
+ return SDL_version_to_Array(&version);
141
+ }
142
+
143
+ static VALUE libsdl_revision(void)
144
+ {
145
+ return rb_usascii_str_new_cstr(SDL_GetRevision());
146
+ }
147
+
148
+ static VALUE libsdl_revision_number(void)
149
+ {
150
+ return INT2NUM(SDL_GetRevisionNumber());
151
+ }
152
+
153
+ /*
154
+ * Document-module: SDL2
155
+ *
156
+ * Namespace module for Ruby/SDL2.
157
+ *
158
+ */
159
+
160
+ /*
161
+ * Document-class: SDL2::Error
162
+ *
163
+ * An exception class for all Ruby/SDL2 specific errors.
164
+ *
165
+ * @attribute [r] error_code
166
+ * @return [Integer] error code sent from SDL library
167
+ */
168
+ void Init_sdl2_ext(void)
169
+ {
170
+ mSDL2 = rb_define_module("SDL2");
171
+
172
+ rb_define_module_function(mSDL2, "init", SDL2_s_init, 1);
173
+ #define DEFINE_SDL_INIT_CONST(type) \
174
+ rb_define_const(mSDL2, "INIT_" #type, UINT2NUM(SDL_INIT_##type))
175
+
176
+ DEFINE_SDL_INIT_CONST(TIMER);
177
+ DEFINE_SDL_INIT_CONST(AUDIO);
178
+ DEFINE_SDL_INIT_CONST(VIDEO);
179
+ DEFINE_SDL_INIT_CONST(JOYSTICK);
180
+ DEFINE_SDL_INIT_CONST(HAPTIC);
181
+ DEFINE_SDL_INIT_CONST(GAMECONTROLLER);
182
+ DEFINE_SDL_INIT_CONST(EVENTS);
183
+ DEFINE_SDL_INIT_CONST(EVERYTHING);
184
+ DEFINE_SDL_INIT_CONST(NOPARACHUTE);
185
+
186
+ /* SDL's version string */
187
+ rb_define_const(mSDL2, "LIBSDL_VERSION", libsdl_version());
188
+ /* SDL's version array of numbers */
189
+ rb_define_const(mSDL2, "LIBSDL_VERSION_NUMBER", libsdl_version_number());
190
+ /* SDL's revision (from VCS) string */
191
+ rb_define_const(mSDL2, "LIBSDL_REVISION", libsdl_revision());
192
+ /* SDL's revision (from VCS) array of numbers */
193
+ rb_define_const(mSDL2, "LIBSDL_REVISION_NUMBER", libsdl_revision_number());
194
+
195
+ #ifdef HAVE_SDL_IMAGE_H
196
+ {
197
+ const SDL_version* version = IMG_Linked_Version();
198
+ /* SDL_image's version string, only available if SDL_image is linked */
199
+ rb_define_const(mSDL2, "LIBSDL_IMAGE_VERSION", SDL_version_to_String(version));
200
+ /* SDL_image's version array of numbers */
201
+ rb_define_const(mSDL2, "LIBSDL_IMAGE_VERSION_NUMBER", SDL_version_to_Array(version));
202
+ }
203
+ #endif
204
+ #ifdef HAVE_SDL_TTF_H
205
+ {
206
+ const SDL_version* version = TTF_Linked_Version();
207
+ /* SDL_ttf's version string, only available if SDL_ttf is linked */
208
+ rb_define_const(mSDL2, "LIBSDL_TTF_VERSION", SDL_version_to_String(version));
209
+ /* SDL_ttf's version array of numbers */
210
+ rb_define_const(mSDL2, "LIBSDL_TTF_VERSION_NUMBER", SDL_version_to_Array(version));
211
+ }
212
+ #endif
213
+ #ifdef HAVE_SDL_MIXER_H
214
+ {
215
+ const SDL_version* version = Mix_Linked_Version();
216
+ /* SDL_mixer's version string , only available if SDL_mixer is linked */
217
+ rb_define_const(mSDL2, "LIBSDL_MIXER_VERSION", SDL_version_to_String(version));
218
+ /* SDL_mixer's version array of numbers */
219
+ rb_define_const(mSDL2, "LIBSDL_MIXER_VERSION_NUMBER", SDL_version_to_Array(version));
220
+ }
221
+ #endif
222
+
223
+ eSDL2Error = rb_define_class_under(mSDL2, "Error", rb_eStandardError);
224
+ rb_define_attr(eSDL2Error, "error_code", 1, 0);
225
+
226
+ rubysdl2_init_hints();
227
+ rubysdl2_init_video();
228
+ rubysdl2_init_gl();
229
+ rubysdl2_init_messagebox();
230
+ rubysdl2_init_event();
231
+ rubysdl2_init_key();
232
+ rubysdl2_init_mouse();
233
+ rubysdl2_init_joystick();
234
+ rubysdl2_init_gamecontorller();
235
+ rubysdl2_init_timer();
236
+ rubysdl2_init_image();
237
+ rubysdl2_init_mixer();
238
+ rubysdl2_init_ttf();
239
+ rubysdl2_init_filesystem();
240
+ rubysdl2_init_clipboard();
241
+
242
+ rb_set_end_proc(quit, 0);
243
+ return;
244
+ }
@@ -0,0 +1,231 @@
1
+ #include "rubysdl2_internal.h"
2
+ #include <SDL_messagebox.h>
3
+
4
+ static VALUE sym_flags, sym_window, sym_title, sym_message, sym_buttons, sym_color_scheme,
5
+ sym_id, sym_text, sym_bg, sym_button_border, sym_button_bg, sym_button_selected;
6
+
7
+ static inline SDL_Window* Get_SDL_Window_or_NULL(VALUE win)
8
+ {
9
+ if (win == Qnil)
10
+ return NULL;
11
+ else
12
+ return Get_SDL_Window(win);
13
+ }
14
+
15
+ /*
16
+ * @overload show_simple_message_box(flag, title, message, parent)
17
+ * Create a simple modal message box.
18
+ *
19
+ * This function pauses all ruby's threads and
20
+ * the threads are resumed when modal dialog is closed.
21
+ *
22
+ * You can create a message box before calling {SDL2.init}.
23
+ *
24
+ * You specify one of the following constants as flag
25
+ *
26
+ * * {SDL2::MESSAGEBOX_ERROR}
27
+ * * {SDL2::MESSAGEBOX_WARNING}
28
+ * * {SDL2::MESSAGEBOX_INFORMATION}
29
+ *
30
+ * @example show warning dialog
31
+ *
32
+ * SDL2.show_simple_message_box(SDL2::MESSAGEBOX_WARNING, "warning!",
33
+ * "Somewhat special warning message!!", nil)
34
+ *
35
+ * @param [Integer] flag one of the above flags
36
+ * @param [String] title title text
37
+ * @param [String] message message text
38
+ * @param [SDL2::Window,nil] parent the parent window, or nil for no parent
39
+ * @return [nil]
40
+ *
41
+ * @see .show_message_box
42
+ */
43
+ static VALUE SDL2_s_show_simple_message_box(VALUE self, VALUE flag, VALUE title,
44
+ VALUE message, VALUE parent)
45
+ {
46
+ title = rb_str_export_to_utf8(title);
47
+ message = rb_str_export_to_utf8(message);
48
+ HANDLE_ERROR(SDL_ShowSimpleMessageBox(NUM2UINT(flag),
49
+ StringValueCStr(title),
50
+ StringValueCStr(message),
51
+ Get_SDL_Window_or_NULL(parent)));
52
+ return Qnil;
53
+ }
54
+
55
+ static void set_color_scheme(VALUE colors, VALUE sym, SDL_MessageBoxColor* color)
56
+ {
57
+ VALUE c = rb_hash_aref(colors, sym);
58
+ Check_Type(c, T_ARRAY);
59
+ color->r = NUM2UCHAR(rb_ary_entry(c, 0));
60
+ color->g = NUM2UCHAR(rb_ary_entry(c, 1));
61
+ color->b = NUM2UCHAR(rb_ary_entry(c, 2));
62
+ }
63
+
64
+ /*
65
+ * @overload show_message_box(flag:, window: nil, title:, message:, buttons:, color_scheme: nil)
66
+ * Create a model message box.
67
+ *
68
+ * You specify one of the following constants as flag
69
+ *
70
+ * * {SDL2::MESSAGEBOX_ERROR}
71
+ * * {SDL2::MESSAGEBOX_WARNING}
72
+ * * {SDL2::MESSAGEBOX_INFORMATION}
73
+ *
74
+ * One button in the dialog represents a hash with folloing elements.
75
+ *
76
+ * { flags: 0, SDL2::MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, or
77
+ * SDL2::MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
78
+ * you can ignore it for 0,
79
+ * text: text of a button,
80
+ * id: index of the button
81
+ * }
82
+ *
83
+ * and buttons is an array of above button hashes.
84
+ *
85
+ * You can specify the color of message box by color_scheme.
86
+ * color_scheme is an hash whose keys are :bg, :text, :button_border, :button_bg,
87
+ * and :button_selected and values are array of three integers representing
88
+ * color.
89
+ * You can also use default color scheme by giving nil.
90
+ *
91
+ *
92
+ * This function pauses all ruby's threads until
93
+ * the modal dialog is closed.
94
+ *
95
+ * You can create a message box before calling {SDL2.init}.
96
+ *
97
+ * @example show a dialog with 3 buttons
98
+ * button = SDL2.show_message_box(flags: SDL2::MESSAGEBOX_WARNING,
99
+ * window: nil,
100
+ * title: "Warning window",
101
+ * message: "Here is the warning message",
102
+ * buttons: [ { # flags is ignored
103
+ * id: 0,
104
+ * text: "No",
105
+ * },
106
+ * {flags: SDL2::MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
107
+ * id: 1,
108
+ * text: "Yes",
109
+ * },
110
+ * {flags: SDL2::MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
111
+ * id: 2,
112
+ * text: "Cancel",
113
+ * },
114
+ * ],
115
+ * color_scheme: {
116
+ * bg: [255, 0, 0],
117
+ * text: [0, 255, 0],
118
+ * button_border: [255, 0, 0],
119
+ * button_bg: [0, 0, 255],
120
+ * button_selected: [255, 0, 0]
121
+ * }
122
+ * )
123
+ *
124
+ * @param [Integer] flags message box type flag
125
+ * @param [SDL2::Window,nil] window the parent window, or nil for no parent
126
+ * @param [String] title the title text
127
+ * @param [String] message the message text
128
+ * @param [Array<Hash<Symbol => Object>>] buttons array of buttons
129
+ * @param [Hash<Symbol=>[Integer,Integer,Integer]> nil] color_scheme
130
+ * color scheme, or nil for the default color scheme
131
+ * @return [Integer] pressed button id
132
+ *
133
+ * @see .show_simple_message_box
134
+ */
135
+ static VALUE SDL2_s_show_message_box(VALUE self, VALUE params)
136
+ {
137
+ SDL_MessageBoxData mb_data;
138
+ VALUE title, message, texts, buttons, color_scheme;
139
+ long num_buttons;
140
+ int i;
141
+ SDL_MessageBoxButtonData* button_data;
142
+ SDL_MessageBoxColorScheme scheme;
143
+ int buttonid;
144
+
145
+ Check_Type(params, T_HASH);
146
+ mb_data.flags = NUM2INT(rb_hash_aref(params, sym_flags));
147
+ mb_data.window = Get_SDL_Window_or_NULL(rb_hash_aref(params, sym_window));
148
+ title = rb_str_export_to_utf8(rb_hash_aref(params, sym_title));
149
+ mb_data.title = StringValueCStr(title);
150
+ message = rb_str_export_to_utf8(rb_hash_aref(params, sym_message));
151
+ mb_data.message = StringValueCStr(message);
152
+
153
+ buttons = rb_hash_aref(params, sym_buttons);
154
+ Check_Type(buttons, T_ARRAY);
155
+ mb_data.numbuttons = num_buttons = RARRAY_LEN(buttons);
156
+ button_data = ALLOCA_N(SDL_MessageBoxButtonData, num_buttons);
157
+ mb_data.buttons = button_data;
158
+ texts = rb_ary_new2(num_buttons);
159
+
160
+ for (i=0; i<num_buttons; ++i) {
161
+ VALUE button = rb_ary_entry(buttons, i);
162
+ VALUE flags = rb_hash_aref(button, sym_flags);
163
+ VALUE text;
164
+ if (flags == Qnil)
165
+ button_data[i].flags = 0;
166
+ else
167
+ button_data[i].flags = NUM2INT(flags);
168
+ text = rb_str_export_to_utf8(rb_hash_aref(button, sym_text));
169
+ rb_ary_push(texts, text);
170
+ button_data[i].buttonid = NUM2INT(rb_hash_aref(button, sym_id));
171
+ button_data[i].text = StringValueCStr(text);
172
+ }
173
+
174
+ color_scheme = rb_hash_aref(params, sym_color_scheme);
175
+ if (color_scheme == Qnil) {
176
+ mb_data.colorScheme = NULL;
177
+ } else {
178
+ Check_Type(color_scheme, T_HASH);
179
+ mb_data.colorScheme = &scheme;
180
+ set_color_scheme(color_scheme, sym_bg, &scheme.colors[0]);
181
+ set_color_scheme(color_scheme, sym_text, &scheme.colors[1]);
182
+ set_color_scheme(color_scheme, sym_button_border, &scheme.colors[2]);
183
+ set_color_scheme(color_scheme, sym_button_bg, &scheme.colors[3]);
184
+ set_color_scheme(color_scheme, sym_button_selected, &scheme.colors[4]);
185
+ }
186
+
187
+ HANDLE_ERROR(SDL_ShowMessageBox(&mb_data, &buttonid));
188
+
189
+ RB_GC_GUARD(title); RB_GC_GUARD(message); RB_GC_GUARD(texts);
190
+ return INT2NUM(buttonid);
191
+ }
192
+
193
+ void rubysdl2_init_messagebox(void)
194
+ {
195
+ rb_define_singleton_method(mSDL2, "show_simple_message_box",
196
+ SDL2_s_show_simple_message_box, 4);
197
+ rb_define_singleton_method(mSDL2, "show_message_box", SDL2_s_show_message_box, 1);
198
+ /* This flag means that the message box shows an error message in
199
+ * {SDL2.show_simple_message_box} and {SDL2.show_message_box}.
200
+ */
201
+ rb_define_const(mSDL2, "MESSAGEBOX_ERROR", INT2NUM(SDL_MESSAGEBOX_ERROR));
202
+ /* This flag means that the message box shows a warning message in
203
+ * {SDL2.show_simple_message_box} and {SDL2.show_message_box}.
204
+ */
205
+ rb_define_const(mSDL2, "MESSAGEBOX_WARNING", INT2NUM(SDL_MESSAGEBOX_WARNING));
206
+ /* This flag means that the message box shows an informational message in
207
+ * {SDL2.show_simple_message_box} and {SDL2.show_message_box}.
208
+ */
209
+ rb_define_const(mSDL2, "MESSAGEBOX_INFORMATION", INT2NUM(SDL_MESSAGEBOX_INFORMATION));
210
+ /* This flag represents the button is selected when return key is pressed in
211
+ * {SDL2.show_message_box}. */
212
+ rb_define_const(mSDL2, "MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT",
213
+ INT2NUM(SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT));
214
+ /* This flag represents the button is selected when escape key is pressed in
215
+ * {SDL2.show_message_box}. */
216
+ rb_define_const(mSDL2, "MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT",
217
+ INT2NUM(SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT));
218
+
219
+ sym_flags = ID2SYM(rb_intern("flags"));
220
+ sym_window = ID2SYM(rb_intern("window"));
221
+ sym_message = ID2SYM(rb_intern("message"));
222
+ sym_title = ID2SYM(rb_intern("title"));
223
+ sym_buttons = ID2SYM(rb_intern("buttons"));
224
+ sym_color_scheme = ID2SYM(rb_intern("color_scheme"));
225
+ sym_id = ID2SYM(rb_intern("id"));
226
+ sym_text = ID2SYM(rb_intern("text"));
227
+ sym_bg = ID2SYM(rb_intern("bg"));
228
+ sym_button_border = ID2SYM(rb_intern("button_border"));
229
+ sym_button_bg = ID2SYM(rb_intern("button_bg"));
230
+ sym_button_selected = ID2SYM(rb_intern("button_selected"));
231
+ }