1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
/* raylib mrbgem entry point.
*
* The bulk of the bindings (all supported structs/enums/functions) are generated
* into raylib_gen.c by tools/gen_raylib.rb from raylib's official raylib_api.json.
* This file only holds the hand-written pieces the generator can't express:
* - platform detection (Rl._is_web)
* - the web main-loop seam (Rl._run_web_loop)
* - Rl.update_texture (UpdateTexture has a `const void *pixels` arg the
* generator skips; takes a Texture + a binary String of raw bytes)
* and calls the generated registrar.
*/
#include <mruby.h>
#include <mruby/data.h> /* DATA_PTR (unchecked struct accessor) */
#include <mruby/string.h> /* RSTRING_PTR */
#include <raylib.h>
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
/* defined in the generated raylib_gen.c */
void rl_define_generated(mrb_state *mrb);
/*
* SMAA lookup textures (baked canonical bytes from iryoku/smaa, generated into
* smaa_tex_data.c by tools/gen_smaa_tex.rb). Exposed to Ruby as Strings so the
* Jamstack::FX::Smaa composite (mrblib/smaa.rb) can upload them via
* Rl.update_texture. Lives in C (not a Ruby literal) because a ~358KB string
* literal both exceeds mruby's 65534-char literal cap AND hangs the irep loader
* at boot; mrb_str_new at runtime has neither limit.
*/
extern const unsigned char smaa_area_tex[];
extern const unsigned char smaa_search_tex[];
static const size_t smaa_area_tex_len = 358400;
static const size_t smaa_search_tex_len = 4096;
static mrb_value
rl_smaa_area_bytes(mrb_state *mrb, mrb_value self)
{
return mrb_str_new(mrb, (const char *)smaa_area_tex, smaa_area_tex_len);
}
static mrb_value
rl_smaa_search_bytes(mrb_state *mrb, mrb_value self)
{
return mrb_str_new(mrb, (const char *)smaa_search_tex, smaa_search_tex_len);
}
/*
* Rl.update_texture(texture, bytes) -> nil
*
* Wraps raylib's UpdateTexture: uploads raw pixel bytes into an existing GPU
* Texture2D. The generator skips UpdateTexture (and LoadImageFromMemory) because
* their `const void *` args aren't auto-marshalable; this helper unpacks a Ruby
* String of raw bytes. Used by Jamstack::FX::Smaa to upload the generated
* area/search lookup textures (RGBA8). The texture's .format must match the byte
* layout (gen_image_color + load_texture_from_image yields RGBA8). Bytes may
* contain NULs — UpdateTexture reads width*height*bpp, not a C string.
*
* Texture2D is accessed via DATA_PTR (unchecked) rather than the static
* rl_ptr_Texture accessor in raylib_gen.c; the call site always passes a Texture.
*/
static mrb_value
rl_update_texture(mrb_state *mrb, mrb_value self)
{
mrb_value tex_val, bytes_val;
mrb_get_args(mrb, "oS", &tex_val, &bytes_val);
UpdateTexture(*((Texture2D *)DATA_PTR(tex_val)), RSTRING_PTR(bytes_val));
return mrb_nil_value();
}
/*
* FilePathList#path_at(index) -> String | nil
*
* Returns the path at the given index. The generated FilePathList struct
* wrapper only exposes `count`/`count=`; the `paths` member (char**) is
* a raw pointer the generator skips. This hand-written method provides
* indexed access for the drag-drop fallback in study-player Phase 2.
*/
static mrb_value
rl_fl_path_at(mrb_state *mrb, mrb_value self)
{
mrb_int idx;
mrb_get_args(mrb, "i", &idx);
FilePathList *fl = (FilePathList *)DATA_PTR(self);
if (!fl || !fl->paths || idx < 0 || idx >= (mrb_int)fl->count)
return mrb_nil_value();
return mrb_str_new_cstr(mrb, fl->paths[idx]);
}
static mrb_value
rl_is_web(mrb_state *mrb, mrb_value self)
{
#ifdef __EMSCRIPTEN__
return mrb_true_value();
#else
return mrb_false_value();
#endif
}
#ifdef __EMSCRIPTEN__
static mrb_state *g_loop_mrb = NULL;
static mrb_value g_loop_block;
static void
web_frame(void)
{
mrb_yield(g_loop_mrb, g_loop_block, mrb_nil_value());
}
static mrb_value
rl_run_web_loop(mrb_state *mrb, mrb_value self)
{
mrb_value blk;
mrb_get_args(mrb, "&", &blk);
g_loop_mrb = mrb;
g_loop_block = blk;
mrb_gc_register(mrb, blk);
emscripten_set_main_loop(web_frame, 0, 1); /* unwinds; never returns */
return mrb_nil_value();
}
#else
static mrb_value
rl_run_web_loop(mrb_state *mrb, mrb_value self)
{
return mrb_nil_value();
}
#endif
void
mrb_raylib_gem_init(mrb_state *mrb)
{
rl_define_generated(mrb);
struct RClass *rl = mrb_define_module(mrb, "Rl");
mrb_define_module_function(mrb, rl, "_is_web", rl_is_web, MRB_ARGS_NONE());
mrb_define_module_function(mrb, rl, "_run_web_loop", rl_run_web_loop, MRB_ARGS_BLOCK());
mrb_define_module_function(mrb, rl, "update_texture", rl_update_texture, MRB_ARGS_REQ(2));
mrb_define_module_function(mrb, rl, "smaa_area_bytes", rl_smaa_area_bytes, MRB_ARGS_NONE());
mrb_define_module_function(mrb, rl, "smaa_search_bytes", rl_smaa_search_bytes, MRB_ARGS_NONE());
/* FilePathList#path_at: indexed access to dropped file paths (generator skips char**). */
{
struct RClass *flc = mrb_class_get_under(mrb, rl, "FilePathList");
mrb_define_method(mrb, flc, "path_at", rl_fl_path_at, MRB_ARGS_REQ(1));
}
}
void
mrb_raylib_gem_final(mrb_state *mrb)
{
}
|