Skip to content

Commit 579dd14

Browse files
committed
Add basic SDL2 example
1 parent 16be882 commit 579dd14

4 files changed

Lines changed: 220 additions & 2 deletions

File tree

CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ set(EXAMPLES
1313
using-cdata
1414
kwargs
1515
blocks
16-
compiling-bytecode)
16+
compiling-bytecode
17+
sdl-wrapper)
1718

1819
set(CMAKE_C_STANDARD 99)
1920
set(WARNINGS -pedantic -Wall -Wshadow -Wpointer-arith
2021
-Wno-missing-braces -Wcast-qual -Wstrict-prototypes)
2122

23+
find_package(SDL2 REQUIRED)
24+
include_directories(${SDL2_INCLUDE_DIRS})
25+
2226
foreach(EXAMPLE ${EXAMPLES})
2327
set(OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin/${EXAMPLE}")
2428

@@ -35,6 +39,11 @@ foreach(EXAMPLE ${EXAMPLES})
3539

3640
target_compile_options(${EXAMPLE} PRIVATE ${WARNINGS})
3741
target_link_libraries(${EXAMPLE} PRIVATE -lmruby -lm)
42+
43+
if("${EXAMPLE}" MATCHES "sdl")
44+
target_include_directories(${EXAMPLE} PRIVATE ${SDL2_INCLUDE_DIRS})
45+
target_link_libraries(${EXAMPLE} PRIVATE ${SDL2_LIBRARIES})
46+
endif()
3847
endforeach()
3948

4049
message(STATUS "Binaries will be placed on the bin/ directory relative to the project root")

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,22 @@ Pacman:
2626
sudo pacman -S mruby
2727
```
2828

29+
### Other requirements
30+
31+
Some examples require SDL2. Install it:
32+
```console
33+
$ sudo apt install libsdl2-dev
34+
```
35+
36+
or
37+
38+
```
39+
$ sudo dnf install SDL2-devel
40+
```
41+
2942
### Compiling
3043

31-
Use the followings commands
44+
Use the followings commands:
3245

3346
```console
3447
cmake -S . -B build
@@ -39,6 +52,8 @@ cmake --build build
3952

4053
Examples included here:
4154

55+
### Basic
56+
4257
| Example | Description |
4358
|:---------------------------------------------:| --------------------------------------------------------------- |
4459
| [hello-world](src/hello-world/) | Classic hello world. |
@@ -52,6 +67,12 @@ Examples included here:
5267
| [blocks](src/blocks/) | Interact with Ruby's block from C. |
5368
| [compiling-bytecode](src/compiling-bytecode/) | Compile Ruby code into bytecode format and save it on the disk. |
5469

70+
### SDL2
71+
72+
| Example | Description |
73+
|:------------------------------:| --------------------------------------------- |
74+
| [sdl-wrapper](src/sdl-wrapper) | Basic wrapper around SDL2 to create a window. |
75+
5576
## Credits
5677

5778
Credits where due, here are some helpful articles/post/resources that helped

src/sdl-wrapper/sdl-wrapper.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#include <stdio.h>
2+
3+
#include <SDL2/SDL.h>
4+
5+
#include <mruby.h>
6+
#include <mruby/class.h>
7+
#include <mruby/compile.h>
8+
#include <mruby/data.h>
9+
#include <mruby/value.h>
10+
#include <mruby/version.h>
11+
12+
/* Declarations */
13+
14+
void freeWindow(mrb_state *mrb, void *ptr);
15+
16+
typedef struct {
17+
SDL_Window *win;
18+
SDL_Renderer *ren;
19+
SDL_Event e; // Event handler
20+
} SDLWindowData;
21+
22+
static const mrb_data_type SDLWindowType = { "Window", freeWindow };
23+
24+
struct RClass *windowKlass;
25+
26+
/* Functions */
27+
28+
static mrb_value mrb_window_new(mrb_state *mrb, mrb_value self) {
29+
char *title;
30+
mrb_int w, h;
31+
mrb_get_args(mrb, "zii", &title, &w, &h);
32+
33+
SDLWindowData *data = (SDLWindowData *)DATA_PTR(self);
34+
if (data != NULL) {
35+
freeWindow(mrb, data);
36+
}
37+
38+
// Init stuff ...
39+
mrb_data_init(self, NULL, &SDLWindowType);
40+
data = (SDLWindowData *)malloc(sizeof(SDLWindowData));
41+
42+
data->win = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, 0);
43+
data->ren = SDL_CreateRenderer(data->win, -1, SDL_RENDERER_ACCELERATED);
44+
45+
mrb_data_init(self, data, &SDLWindowType);
46+
47+
return self;
48+
}
49+
50+
/* This functions polls the events from SDL and returns the type of the current event */
51+
static mrb_value mrb_window_get_events(mrb_state *mrb, mrb_value self) {
52+
SDLWindowData *idata;
53+
Data_Get_Struct(mrb, self, &SDLWindowType, idata);
54+
55+
SDL_PollEvent(&idata->e);
56+
57+
return mrb_fixnum_value(idata->e.type);
58+
}
59+
60+
static mrb_value mrb_window_get_scancode(mrb_state *mrb, mrb_value self) {
61+
SDLWindowData *idata;
62+
Data_Get_Struct(mrb, self, &SDLWindowType, idata);
63+
64+
return mrb_fixnum_value(idata->e.key.keysym.sym);
65+
}
66+
67+
static mrb_value mrb_window_render_set_color(mrb_state *mrb, mrb_value self) {
68+
mrb_int r, g, b, a;
69+
mrb_get_args(mrb, "iiii", &r, &g, &b, &a);
70+
71+
SDLWindowData *idata;
72+
Data_Get_Struct(mrb, self, &SDLWindowType, idata);
73+
74+
SDL_SetRenderDrawColor(idata->ren, r, g, b, a);
75+
76+
return mrb_nil_value();
77+
}
78+
79+
static mrb_value mrb_window_render_clear(mrb_state *mrb, mrb_value self) {
80+
SDLWindowData *idata;
81+
Data_Get_Struct(mrb, self, &SDLWindowType, idata);
82+
83+
SDL_RenderClear(idata->ren);
84+
85+
return mrb_nil_value();
86+
}
87+
88+
static mrb_value mrb_window_render_present(mrb_state *mrb, mrb_value self) {
89+
SDLWindowData *idata;
90+
Data_Get_Struct(mrb, self, &SDLWindowType, idata);
91+
92+
SDL_RenderPresent(idata->ren);
93+
94+
return mrb_nil_value();
95+
}
96+
97+
static void appendMRubyFunctions(mrb_state *mrb) {
98+
windowKlass = mrb_define_class(mrb, "SDLWindow", mrb->object_class);
99+
MRB_SET_INSTANCE_TT(windowKlass, MRB_TT_DATA);
100+
101+
mrb_define_method(mrb, windowKlass, "initialize", mrb_window_new, MRB_ARGS_REQ(1));
102+
mrb_define_method(mrb, windowKlass, "poll_event", mrb_window_get_events, MRB_ARGS_NONE());
103+
mrb_define_method(mrb, windowKlass, "scancode", mrb_window_get_scancode, MRB_ARGS_NONE());
104+
mrb_define_method(mrb, windowKlass, "render_color", mrb_window_render_set_color, MRB_ARGS_REQ(4));
105+
mrb_define_method(mrb, windowKlass, "render_clear", mrb_window_render_clear, MRB_ARGS_NONE());
106+
mrb_define_method(mrb, windowKlass, "render_present", mrb_window_render_present, MRB_ARGS_NONE());
107+
}
108+
109+
static void appendSDLConstants(mrb_state *mrb) {
110+
// Events
111+
mrb_define_const(mrb, mrb->kernel_module, "SDL_EVENT_QUIT", mrb_fixnum_value(SDL_QUIT));
112+
mrb_define_const(mrb, mrb->kernel_module, "SDL_EVENT_KEY_DOWN", mrb_fixnum_value(SDL_KEYDOWN));
113+
114+
// Scancodes
115+
mrb_define_const(mrb, mrb->kernel_module, "SDLK_ESC", mrb_fixnum_value(SDLK_ESCAPE));
116+
}
117+
118+
int main(void) {
119+
fprintf(stdout, "MRuby version %s", MRUBY_VERSION);
120+
121+
mrb_state *mrb = mrb_open();
122+
if (!mrb) {
123+
fprintf(stderr, "Couldn't initialize MRuby\n");
124+
return 1;
125+
}
126+
127+
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
128+
fprintf(stderr, "SDL2: Failed to initialize!\n");
129+
fprintf(stderr, "Error: %s\n", SDL_GetError());
130+
}
131+
132+
appendMRubyFunctions(mrb);
133+
appendSDLConstants(mrb);
134+
135+
// Open our file
136+
FILE *rubyScript = fopen("window.rb", "r");
137+
if (!rubyScript) {
138+
fprintf(stderr, "Couldn't find a main.rb file in the current directory, quitting...\n");
139+
mrb_close(mrb);
140+
return 1;
141+
}
142+
143+
// Pass it to MRuby
144+
mrb_load_file(mrb, rubyScript);
145+
146+
fclose(rubyScript);
147+
148+
if (mrb->exc) {
149+
mrb_print_error(mrb);
150+
}
151+
152+
SDL_Quit();
153+
mrb_close(mrb);
154+
return 0;
155+
}
156+
157+
void freeWindow(mrb_state *mrb, void *ptr) {
158+
SDLWindowData *data = (SDLWindowData *)ptr;
159+
if (data != NULL) {
160+
if (data->ren != NULL) {
161+
SDL_DestroyRenderer(data->ren);
162+
}
163+
164+
if (data->win != NULL) {
165+
SDL_DestroyWindow(data->win);
166+
}
167+
168+
mrb_free(mrb, data);
169+
}
170+
}

src/sdl-wrapper/window.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This file is loaded everytime the executable is ran. Feel free to edit it!
2+
3+
@window = SDLWindow.new('MRuby SDL Wrapper', 250, 250)
4+
@running = true
5+
6+
while @running
7+
# Event based programming
8+
case @window.poll_event
9+
when SDL_EVENT_QUIT
10+
@running = false
11+
when SDL_EVENT_KEY_DOWN
12+
@running = false if @window.scancode == SDLK_ESC
13+
end
14+
15+
@window.render_color(255, 100, 100, 255)
16+
@window.render_clear
17+
@window.render_present
18+
end

0 commit comments

Comments
 (0)