nuklear 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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +29 -0
- data/LICENSE.txt +21 -0
- data/README.md +196 -0
- data/Rakefile +26 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/arial.ttf +0 -0
- data/examples/calculator.rb +102 -0
- data/examples/hello_nuklear.rb +182 -0
- data/examples/lib/opengl_font.rb +32 -0
- data/examples/lib/opengl_init.rb +4 -0
- data/examples/lib/sdl2_init.rb +6 -0
- data/examples/lib/sdl2_input.rb +81 -0
- data/examples/lib/window.rb +47 -0
- data/ext/freetype/extconf.rb +26 -0
- data/ext/nuklear/extconf.rb +14 -0
- data/ext/nuklear/nkrb.c +79 -0
- data/ext/nuklear/nkrb.h +89 -0
- data/ext/nuklear/nkrb_buffer.c +80 -0
- data/ext/nuklear/nkrb_context.c +241 -0
- data/ext/nuklear/nkrb_font.c +80 -0
- data/ext/nuklear/nkrb_renderer.c +114 -0
- data/ext/nuklear/nkrb_style.c +61 -0
- data/ext/nuklear/nkrb_style_color.c +126 -0
- data/ext/nuklear/nkrb_style_image.c +32 -0
- data/ext/nuklear/nkrb_ui.c +32 -0
- data/ext/nuklear/nkrb_ui_builder.c +29 -0
- data/ext/nuklear/nkrb_ui_button.c +55 -0
- data/ext/nuklear/nkrb_ui_color_picker.c +20 -0
- data/ext/nuklear/nkrb_ui_combo.c +73 -0
- data/ext/nuklear/nkrb_ui_container.c +7 -0
- data/ext/nuklear/nkrb_ui_edit_string.c +38 -0
- data/ext/nuklear/nkrb_ui_group.c +27 -0
- data/ext/nuklear/nkrb_ui_label.c +30 -0
- data/ext/nuklear/nkrb_ui_layout.c +125 -0
- data/ext/nuklear/nkrb_ui_menu.c +49 -0
- data/ext/nuklear/nkrb_ui_menu_item.c +30 -0
- data/ext/nuklear/nkrb_ui_menubar.c +18 -0
- data/ext/nuklear/nkrb_ui_popup.c +24 -0
- data/ext/nuklear/nkrb_ui_progress.c +19 -0
- data/ext/nuklear/nkrb_ui_property.c +20 -0
- data/ext/nuklear/nkrb_ui_selectables.c +53 -0
- data/ext/nuklear/nkrb_ui_slider.c +19 -0
- data/ext/nuklear/nkrb_ui_tree.c +29 -0
- data/ext/nuklear/nkrb_ui_widget.c +7 -0
- data/ext/nuklear/nkrb_ui_window.c +43 -0
- data/ext/nuklear/nuklear.h +23378 -0
- data/ext/nuklear_renderer_opengl2/KHR/khrplatform.h +285 -0
- data/ext/nuklear_renderer_opengl2/extconf.rb +13 -0
- data/ext/nuklear_renderer_opengl2/glad.c +1432 -0
- data/ext/nuklear_renderer_opengl2/glad.h +2747 -0
- data/ext/nuklear_renderer_opengl2/nuklear_renderer_opengl2.c +197 -0
- data/ext/nuklear_renderer_opengl4/KHR/khrplatform.h +285 -0
- data/ext/nuklear_renderer_opengl4/extconf.rb +13 -0
- data/ext/nuklear_renderer_opengl4/glad.c +1782 -0
- data/ext/nuklear_renderer_opengl4/glad.h +3687 -0
- data/ext/nuklear_renderer_opengl4/nuklear_renderer_opengl4.c +255 -0
- data/lib/nuklear/context.rb +49 -0
- data/lib/nuklear/dsl.rb +46 -0
- data/lib/nuklear/event_buffer.rb +23 -0
- data/lib/nuklear/renderer/opengl24.rb +13 -0
- data/lib/nuklear/renderer.rb +108 -0
- data/lib/nuklear/style/color.rb +24 -0
- data/lib/nuklear/style/image.rb +9 -0
- data/lib/nuklear/style.rb +8 -0
- data/lib/nuklear/test_case.rb +30 -0
- data/lib/nuklear/ui/base.rb +34 -0
- data/lib/nuklear/ui/button.rb +77 -0
- data/lib/nuklear/ui/checkbox.rb +39 -0
- data/lib/nuklear/ui/col.rb +21 -0
- data/lib/nuklear/ui/color_picker.rb +31 -0
- data/lib/nuklear/ui/combo_box.rb +42 -0
- data/lib/nuklear/ui/container.rb +80 -0
- data/lib/nuklear/ui/edit_string.rb +48 -0
- data/lib/nuklear/ui/enableable.rb +29 -0
- data/lib/nuklear/ui/events.rb +23 -0
- data/lib/nuklear/ui/group.rb +31 -0
- data/lib/nuklear/ui/label.rb +21 -0
- data/lib/nuklear/ui/menu.rb +43 -0
- data/lib/nuklear/ui/menu_bar.rb +19 -0
- data/lib/nuklear/ui/menu_item.rb +34 -0
- data/lib/nuklear/ui/option.rb +17 -0
- data/lib/nuklear/ui/option_group.rb +22 -0
- data/lib/nuklear/ui/popup.rb +37 -0
- data/lib/nuklear/ui/progress.rb +33 -0
- data/lib/nuklear/ui/property.rb +28 -0
- data/lib/nuklear/ui/row.rb +28 -0
- data/lib/nuklear/ui/select_list.rb +31 -0
- data/lib/nuklear/ui/selectable.rb +21 -0
- data/lib/nuklear/ui/slider.rb +26 -0
- data/lib/nuklear/ui/text_align.rb +14 -0
- data/lib/nuklear/ui/tree.rb +62 -0
- data/lib/nuklear/ui/window.rb +175 -0
- data/lib/nuklear/ui.rb +33 -0
- data/lib/nuklear/version.rb +3 -0
- data/lib/nuklear.rb +26 -0
- data/nuklear.gemspec +41 -0
- metadata +233 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/* Heavily adapted from https://github.com/vurtun/nuklear/blob/master/demo/sdl_opengl3/nuklear_sdl_gl3.h */
|
|
2
|
+
|
|
3
|
+
#define NK_IMPLEMENTATION
|
|
4
|
+
#include "../nuklear/nuklear.h"
|
|
5
|
+
#include "glad.h"
|
|
6
|
+
#include <ruby.h>
|
|
7
|
+
|
|
8
|
+
#define MAX_VERTEX_MEMORY 512 * 1024
|
|
9
|
+
#define MAX_ELEMENT_MEMORY 128 * 1024
|
|
10
|
+
|
|
11
|
+
VALUE mNuklear = Qnil;
|
|
12
|
+
VALUE cNuklearRenderer = Qnil;
|
|
13
|
+
VALUE cNuklearRendererOpenGL4 = Qnil;
|
|
14
|
+
VALUE cNuklearBuffer = Qnil;
|
|
15
|
+
|
|
16
|
+
#ifdef __APPLE__
|
|
17
|
+
#define NK_SHADER_VERSION "#version 150\n"
|
|
18
|
+
#else
|
|
19
|
+
#define NK_SHADER_VERSION "#version 300 es\n"
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
static const GLchar *vertex_shader =
|
|
23
|
+
NK_SHADER_VERSION
|
|
24
|
+
"uniform mat4 ProjMtx;\n"
|
|
25
|
+
"in vec2 Position;\n"
|
|
26
|
+
"in vec2 TexCoord;\n"
|
|
27
|
+
"in vec4 Color;\n"
|
|
28
|
+
"out vec2 Frag_UV;\n"
|
|
29
|
+
"out vec4 Frag_Color;\n"
|
|
30
|
+
"void main() {\n"
|
|
31
|
+
" Frag_UV = TexCoord;\n"
|
|
32
|
+
" Frag_Color = Color;\n"
|
|
33
|
+
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
|
|
34
|
+
"}\n";
|
|
35
|
+
|
|
36
|
+
static const GLchar *fragment_shader =
|
|
37
|
+
NK_SHADER_VERSION
|
|
38
|
+
"precision mediump float;\n"
|
|
39
|
+
"uniform sampler2D Texture;\n"
|
|
40
|
+
"in vec2 Frag_UV;\n"
|
|
41
|
+
"in vec4 Frag_Color;\n"
|
|
42
|
+
"out vec4 Out_Color;\n"
|
|
43
|
+
"void main(){\n"
|
|
44
|
+
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
|
45
|
+
"}\n";
|
|
46
|
+
|
|
47
|
+
struct vertex {
|
|
48
|
+
float position[2];
|
|
49
|
+
float uv[2];
|
|
50
|
+
nk_byte col[4];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
void nuklear_command_buffer_free(struct nk_buffer *buf) {
|
|
54
|
+
nk_buffer_free(buf);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
VALUE renderer_initialize(VALUE self, VALUE context) {
|
|
58
|
+
if (!gladLoadGL())
|
|
59
|
+
rb_raise(rb_eStandardError, "Failed to init GLAD");
|
|
60
|
+
// printf("OpenGL %s, GLSL %s\n", glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION));
|
|
61
|
+
|
|
62
|
+
rb_call_super(1, &context);
|
|
63
|
+
|
|
64
|
+
int status;
|
|
65
|
+
int prog = glCreateProgram();
|
|
66
|
+
int vert_shdr = glCreateShader(GL_VERTEX_SHADER);
|
|
67
|
+
int frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
|
|
68
|
+
glShaderSource(vert_shdr, 1, &vertex_shader, 0);
|
|
69
|
+
glShaderSource(frag_shdr, 1, &fragment_shader, 0);
|
|
70
|
+
glCompileShader(vert_shdr);
|
|
71
|
+
glCompileShader(frag_shdr);
|
|
72
|
+
glGetShaderiv(vert_shdr, GL_COMPILE_STATUS, &status);
|
|
73
|
+
assert(status == GL_TRUE);
|
|
74
|
+
glGetShaderiv(frag_shdr, GL_COMPILE_STATUS, &status);
|
|
75
|
+
assert(status == GL_TRUE);
|
|
76
|
+
glAttachShader(prog, vert_shdr);
|
|
77
|
+
glAttachShader(prog, frag_shdr);
|
|
78
|
+
glLinkProgram(prog);
|
|
79
|
+
glGetProgramiv(prog, GL_LINK_STATUS, &status);
|
|
80
|
+
assert(status == GL_TRUE);
|
|
81
|
+
|
|
82
|
+
int uniform_tex = glGetUniformLocation(prog, "Texture");
|
|
83
|
+
int uniform_proj = glGetUniformLocation(prog, "ProjMtx");
|
|
84
|
+
int attrib_pos = glGetAttribLocation(prog, "Position");
|
|
85
|
+
int attrib_uv = glGetAttribLocation(prog, "TexCoord");
|
|
86
|
+
int attrib_col = glGetAttribLocation(prog, "Color");
|
|
87
|
+
|
|
88
|
+
/* buffer setup */
|
|
89
|
+
GLsizei vs = sizeof(struct vertex);
|
|
90
|
+
size_t vp = offsetof(struct vertex, position);
|
|
91
|
+
size_t vt = offsetof(struct vertex, uv);
|
|
92
|
+
size_t vc = offsetof(struct vertex, col);
|
|
93
|
+
|
|
94
|
+
GLuint vbo, ebo, vao;
|
|
95
|
+
|
|
96
|
+
glGenBuffers(1, &vbo);
|
|
97
|
+
glGenBuffers(1, &ebo);
|
|
98
|
+
glGenVertexArrays(1, &vao);
|
|
99
|
+
|
|
100
|
+
glBindVertexArray(vao);
|
|
101
|
+
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
102
|
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
|
103
|
+
|
|
104
|
+
glEnableVertexAttribArray((GLuint)attrib_pos);
|
|
105
|
+
glEnableVertexAttribArray((GLuint)attrib_uv);
|
|
106
|
+
glEnableVertexAttribArray((GLuint)attrib_col);
|
|
107
|
+
|
|
108
|
+
glVertexAttribPointer((GLuint)attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
|
|
109
|
+
glVertexAttribPointer((GLuint)attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
|
|
110
|
+
glVertexAttribPointer((GLuint)attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
|
|
111
|
+
|
|
112
|
+
glBindTexture(GL_TEXTURE_2D, 0);
|
|
113
|
+
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
114
|
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
115
|
+
glBindVertexArray(0);
|
|
116
|
+
|
|
117
|
+
rb_ivar_set(self, rb_intern("@program"), INT2FIX(prog));
|
|
118
|
+
rb_ivar_set(self, rb_intern("@uniform_tex"), INT2FIX(uniform_tex));
|
|
119
|
+
rb_ivar_set(self, rb_intern("@uniform_proj"), INT2FIX(uniform_proj));
|
|
120
|
+
rb_ivar_set(self, rb_intern("@vao"), INT2FIX(vao));
|
|
121
|
+
rb_ivar_set(self, rb_intern("@vbo"), INT2FIX(vbo));
|
|
122
|
+
rb_ivar_set(self, rb_intern("@ebo"), INT2FIX(ebo));
|
|
123
|
+
|
|
124
|
+
return self;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
VALUE renderer_render_gl(VALUE self) {
|
|
128
|
+
struct nk_context *ctx;
|
|
129
|
+
struct nk_buffer *cmds;
|
|
130
|
+
VALUE window_size = rb_funcall(self, rb_intern("window_size"), 0);
|
|
131
|
+
VALUE drawable_size = rb_funcall(self, rb_intern("drawable_size"), 0);
|
|
132
|
+
VALUE window_width = rb_ary_entry(window_size, 0);
|
|
133
|
+
VALUE window_height = rb_ary_entry(window_size, 1);
|
|
134
|
+
VALUE drawable_width = rb_ary_entry(drawable_size, 0);
|
|
135
|
+
VALUE drawable_height = rb_ary_entry(drawable_size, 1);
|
|
136
|
+
int program = FIX2INT(rb_ivar_get(self, rb_intern("@program")));
|
|
137
|
+
int uniform_tex = FIX2INT(rb_ivar_get(self, rb_intern("@uniform_tex")));
|
|
138
|
+
int uniform_proj = FIX2INT(rb_ivar_get(self, rb_intern("@uniform_proj")));
|
|
139
|
+
int width = FIX2INT(window_width),
|
|
140
|
+
height = FIX2INT(window_height);
|
|
141
|
+
int display_width = FIX2INT(drawable_width),
|
|
142
|
+
display_height = FIX2INT(drawable_height);
|
|
143
|
+
struct nk_draw_null_texture *null_tex;
|
|
144
|
+
struct nk_vec2 scale;
|
|
145
|
+
VALUE context = rb_ivar_get(self, rb_intern("@context"));
|
|
146
|
+
Data_Get_Struct(rb_ivar_get(context, rb_intern("@null")), struct nk_draw_null_texture, null_tex);
|
|
147
|
+
Data_Get_Struct(context, struct nk_context, ctx);
|
|
148
|
+
Data_Get_Struct(rb_ivar_get(self, rb_intern("@commands")), struct nk_buffer, cmds);
|
|
149
|
+
|
|
150
|
+
GLfloat ortho[4][4] = {
|
|
151
|
+
{2.0f, 0.0f, 0.0f, 0.0f},
|
|
152
|
+
{0.0f,-2.0f, 0.0f, 0.0f},
|
|
153
|
+
{0.0f, 0.0f,-1.0f, 0.0f},
|
|
154
|
+
{-1.0f,1.0f, 0.0f, 1.0f},
|
|
155
|
+
};
|
|
156
|
+
ortho[0][0] /= (GLfloat)width;
|
|
157
|
+
ortho[1][1] /= (GLfloat)height;
|
|
158
|
+
|
|
159
|
+
scale.x = (float)display_width/(float)width;
|
|
160
|
+
scale.y = (float)display_height/(float)height;
|
|
161
|
+
|
|
162
|
+
/* setup global state */
|
|
163
|
+
glViewport(0,0,display_width,display_height);
|
|
164
|
+
glEnable(GL_BLEND);
|
|
165
|
+
glBlendEquation(GL_FUNC_ADD);
|
|
166
|
+
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
167
|
+
glDisable(GL_CULL_FACE);
|
|
168
|
+
glDisable(GL_DEPTH_TEST);
|
|
169
|
+
glEnable(GL_SCISSOR_TEST);
|
|
170
|
+
glActiveTexture(GL_TEXTURE0);
|
|
171
|
+
|
|
172
|
+
/* setup program */
|
|
173
|
+
glUseProgram(program);
|
|
174
|
+
glUniform1i(uniform_tex, 0);
|
|
175
|
+
glUniformMatrix4fv(uniform_proj, 1, GL_FALSE, &ortho[0][0]);
|
|
176
|
+
|
|
177
|
+
rb_call_super(0, NULL);
|
|
178
|
+
|
|
179
|
+
glUseProgram(0);
|
|
180
|
+
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
181
|
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
182
|
+
glBindVertexArray(0);
|
|
183
|
+
glDisable(GL_SCISSOR_TEST);
|
|
184
|
+
glEnable(GL_CULL_FACE);
|
|
185
|
+
glEnable(GL_DEPTH_TEST);
|
|
186
|
+
|
|
187
|
+
return self;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
VALUE renderer_nk_convert_gl(VALUE self) {
|
|
191
|
+
VALUE result = rb_call_super(0, NULL);
|
|
192
|
+
|
|
193
|
+
struct nk_buffer *vertices = NULL;
|
|
194
|
+
struct nk_buffer *indices = NULL;
|
|
195
|
+
Data_Get_Struct(rb_funcall(self, rb_intern("vertices"), 0), struct nk_buffer, vertices);
|
|
196
|
+
Data_Get_Struct(rb_funcall(self, rb_intern("vertex_indices"), 0), struct nk_buffer, indices);
|
|
197
|
+
|
|
198
|
+
int vao = FIX2INT(rb_ivar_get(self, rb_intern("@vao")));
|
|
199
|
+
int vbo = FIX2INT(rb_ivar_get(self, rb_intern("@vbo")));
|
|
200
|
+
int ebo = FIX2INT(rb_ivar_get(self, rb_intern("@ebo")));
|
|
201
|
+
glBindVertexArray(vao);
|
|
202
|
+
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
203
|
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
|
204
|
+
glBufferData(GL_ARRAY_BUFFER,
|
|
205
|
+
MAX_VERTEX_MEMORY,
|
|
206
|
+
nk_buffer_memory_const(vertices),
|
|
207
|
+
GL_STREAM_DRAW);
|
|
208
|
+
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
|
209
|
+
MAX_ELEMENT_MEMORY,
|
|
210
|
+
nk_buffer_memory_const(indices),
|
|
211
|
+
GL_STREAM_DRAW);
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
VALUE renderer_draw_gl(VALUE self, VALUE cmd) {
|
|
216
|
+
VALUE window_size = rb_funcall(self, rb_intern("window_size"), 0);
|
|
217
|
+
VALUE drawable_size = rb_funcall(self, rb_intern("drawable_size"), 0);
|
|
218
|
+
VALUE window_width = rb_ary_entry(window_size, 0);
|
|
219
|
+
VALUE window_height = rb_ary_entry(window_size, 1);
|
|
220
|
+
VALUE drawable_width = rb_ary_entry(drawable_size, 0);
|
|
221
|
+
VALUE drawable_height = rb_ary_entry(drawable_size, 1);
|
|
222
|
+
int width = FIX2INT(window_width),
|
|
223
|
+
height = FIX2INT(window_height);
|
|
224
|
+
int display_width = FIX2INT(drawable_width),
|
|
225
|
+
display_height = FIX2INT(drawable_height);
|
|
226
|
+
struct nk_vec2 scale;
|
|
227
|
+
scale.x = (float)display_width/(float)width;
|
|
228
|
+
scale.y = (float)display_height/(float)height;
|
|
229
|
+
|
|
230
|
+
VALUE clip_rect = rb_hash_aref(cmd, ID2SYM(rb_intern("clip_rect")));
|
|
231
|
+
float x = (float) NUM2DBL(RARRAY_AREF(clip_rect, 0));
|
|
232
|
+
float y = (float) NUM2DBL(RARRAY_AREF(clip_rect, 1));
|
|
233
|
+
float w = (float) NUM2DBL(RARRAY_AREF(clip_rect, 2));
|
|
234
|
+
float h = (float) NUM2DBL(RARRAY_AREF(clip_rect, 3));
|
|
235
|
+
glBindTexture(GL_TEXTURE_2D, (GLuint) NUM2UINT(rb_hash_aref(cmd, ID2SYM(rb_intern("texture_handle")))));
|
|
236
|
+
glScissor((GLint)(x * scale.x),
|
|
237
|
+
(GLint)((height - (GLint)(y + h)) * scale.y),
|
|
238
|
+
(GLint)(w * scale.x),
|
|
239
|
+
(GLint)(h * scale.y));
|
|
240
|
+
glDrawElements(GL_TRIANGLES, (GLsizei)NUM2UINT(rb_hash_aref(cmd, ID2SYM(rb_intern("element_count")))),
|
|
241
|
+
GL_UNSIGNED_SHORT, (void *) NUM2UINT(rb_hash_aref(cmd, ID2SYM(rb_intern("offset")))));
|
|
242
|
+
return self;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
void Init_nuklear_renderer_opengl4(void) {
|
|
246
|
+
mNuklear = rb_define_module("Nuklear");
|
|
247
|
+
cNuklearRenderer = rb_define_class_under(mNuklear, "Renderer", rb_cObject);
|
|
248
|
+
cNuklearRendererOpenGL4 = rb_define_class_under(cNuklearRenderer, "OpenGL4", cNuklearRenderer);
|
|
249
|
+
cNuklearBuffer = rb_const_get(mNuklear, rb_intern("Buffer"));
|
|
250
|
+
|
|
251
|
+
rb_define_method(cNuklearRendererOpenGL4, "initialize", renderer_initialize, 1);
|
|
252
|
+
rb_define_method(cNuklearRendererOpenGL4, "nk_convert", renderer_nk_convert_gl, 0);
|
|
253
|
+
rb_define_method(cNuklearRendererOpenGL4, "draw", renderer_draw_gl, 1);
|
|
254
|
+
rb_define_method(cNuklearRendererOpenGL4, "render", renderer_render_gl, 0);
|
|
255
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Nuklear
|
|
2
|
+
class Context
|
|
3
|
+
include Nuklear::UI::Container
|
|
4
|
+
attr_accessor :renderer
|
|
5
|
+
attr_reader :events
|
|
6
|
+
|
|
7
|
+
def events
|
|
8
|
+
@events ||= EventBuffer.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def process_commands
|
|
12
|
+
remaining = commands.dup
|
|
13
|
+
while remaining.any?
|
|
14
|
+
cmd = remaining.shift
|
|
15
|
+
# cmd.tick(delta) if cmd.respond_to?(:tick)
|
|
16
|
+
remaining.concat cmd.commands if cmd.respond_to?(:commands)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Triggers an event. The event name must be one of the symbols defined
|
|
21
|
+
# in Nuklear::EventBuffer::EVENT_NAMES.
|
|
22
|
+
def trigger(event_name, *event_args)
|
|
23
|
+
events.add(event_name, *event_args)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def dsl(&block)
|
|
27
|
+
Nuklear::DSL.new(self, &block)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Draws the UI. This method will be called at the appropriate time in the
|
|
31
|
+
# Nuklear frame update process. It should not be called directly.
|
|
32
|
+
protected def paint
|
|
33
|
+
run_commands(self)
|
|
34
|
+
renderer.render
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Events (window events, input events, etc) will accumulate over time.
|
|
38
|
+
# Nuklear requires these events to be processed at the proper time or else
|
|
39
|
+
# issues could arise. This method will be called at the appropriate time
|
|
40
|
+
# in order to handle the events that have accumulated since the last
|
|
41
|
+
# frame. It should not be called directly.
|
|
42
|
+
protected def process_pending_events
|
|
43
|
+
events.drain do |evt|
|
|
44
|
+
@event_sink.send(*evt)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/nuklear/dsl.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'nuklear/ui'
|
|
2
|
+
|
|
3
|
+
module Nuklear
|
|
4
|
+
class DSL
|
|
5
|
+
def initialize(ctx, &block)
|
|
6
|
+
@ctx = ctx
|
|
7
|
+
instance_eval(&block) if block_given?
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def add_component(klass, *args, **kw, &block)
|
|
11
|
+
# if klass initialize accepts a block, pass the block into that. The
|
|
12
|
+
# caller must call .dsl on the result if they want a nested DSL.
|
|
13
|
+
if block_given? && klass.instance_method(:initialize).parameters.last[0] == :block
|
|
14
|
+
instance = klass.new(*args, **kw, &block)
|
|
15
|
+
@ctx << instance
|
|
16
|
+
else # assume block is for a nested DSL
|
|
17
|
+
instance = klass.new(*args, **kw)
|
|
18
|
+
@ctx << instance
|
|
19
|
+
instance.dsl(&block) if block_given?
|
|
20
|
+
end
|
|
21
|
+
instance
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def method_missing(name, *args, **kw, &block)
|
|
25
|
+
@ctx.send(name, *args, **kw, &block)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def respond_to?(name)
|
|
29
|
+
super || @ctx.respond_to?(name)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Scans all descendants of Nuklear::UI::Base and defines DSL method names
|
|
33
|
+
# based on each component name. This happens once automatically at startup
|
|
34
|
+
# but if you are having trouble with a new custom UI component, then you
|
|
35
|
+
# can call this method to make sure it's been defined.
|
|
36
|
+
def self.prepare!
|
|
37
|
+
Nuklear::UI::Base.descendants.each do |descendant|
|
|
38
|
+
define_method descendant.dsl_method_name do |*args, **kw, &block|
|
|
39
|
+
add_component(descendant, *args, **kw, &block)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
prepare!
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Nuklear
|
|
2
|
+
# Stores staged events waiting to be drained.
|
|
3
|
+
class EventBuffer
|
|
4
|
+
# These correlate to methods defined by Nuklear::Context::EventSink.
|
|
5
|
+
EVENT_NAMES = [:motion, :key, :button, :scroll, :char, :glyph, :unicode]
|
|
6
|
+
|
|
7
|
+
attr_reader :pending_events
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@pending_events = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def drain
|
|
14
|
+
@pending_events.each { |evt| yield(evt) }
|
|
15
|
+
@pending_events.clear
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add(event_name, *event_args)
|
|
19
|
+
super unless EVENT_NAMES.include?(event_name)
|
|
20
|
+
@pending_events << [event_name, *event_args]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Nuklear
|
|
2
|
+
class Renderer
|
|
3
|
+
def self.renderer_class
|
|
4
|
+
if SDL2::GL.get_attribute(SDL2::GL::CONTEXT_MAJOR_VERSION) > 2
|
|
5
|
+
require 'nuklear_renderer_opengl4'
|
|
6
|
+
Nuklear::Renderer::OpenGL4
|
|
7
|
+
else
|
|
8
|
+
require 'nuklear_renderer_opengl2'
|
|
9
|
+
Nuklear::Renderer::OpenGL2
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require 'fiddle/import'
|
|
2
|
+
|
|
3
|
+
module Nuklear
|
|
4
|
+
# This base class provides a pure-Ruby renderer implementation for Nuklear.
|
|
5
|
+
# Importantly, it doesn't actually *draw* anything. Instead it provides a
|
|
6
|
+
# generic renderer implementation where subclasses need only override the
|
|
7
|
+
# #draw method to draw something.
|
|
8
|
+
#
|
|
9
|
+
# In most cases, subclasses will also have to override #initialize to set up
|
|
10
|
+
# one-time state (e.g. compiling shaders), and also #render to set up
|
|
11
|
+
# per-frame state (e.g. activating shaders). In both cases, subclasses
|
|
12
|
+
# should call `super`.
|
|
13
|
+
#
|
|
14
|
+
class Renderer
|
|
15
|
+
attr_accessor :window_size
|
|
16
|
+
attr_writer :drawable_size
|
|
17
|
+
|
|
18
|
+
# Returns the configuration necessary for converting a Nuklear rendering
|
|
19
|
+
# pass into a renderer-specific one. This data can be changed at run-time;
|
|
20
|
+
# it is not cached.
|
|
21
|
+
attr_accessor :convert_config
|
|
22
|
+
|
|
23
|
+
# Assign the handle for a 1x1 white texture to this accessor. It doesn't
|
|
24
|
+
# matter what format this takes, (GL texture ID, memory address of texture
|
|
25
|
+
# data, etc), as long as the renderer can decode this into a usable result
|
|
26
|
+
# when it's passed back to it later on.
|
|
27
|
+
attr_reader :null_texture_handle
|
|
28
|
+
|
|
29
|
+
# Nuklear::Buffer containing vertex data
|
|
30
|
+
attr_reader :vertices
|
|
31
|
+
|
|
32
|
+
# Nuklear::Buffer containing vertex index data
|
|
33
|
+
attr_reader :vertex_indices
|
|
34
|
+
|
|
35
|
+
# Nuklear::Buffer containing command data
|
|
36
|
+
attr_reader :commands
|
|
37
|
+
|
|
38
|
+
# Nuklear::Context for this renderer
|
|
39
|
+
attr_reader :context
|
|
40
|
+
|
|
41
|
+
Vertex = Fiddle::Importer.struct [
|
|
42
|
+
'float position[3]',
|
|
43
|
+
'float uv[3]',
|
|
44
|
+
'unsigned char color[4]'
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
# For all renderer implementations, override #initialize to set up your
|
|
48
|
+
# initial state (e.g. compiling shaders) and call `super`.
|
|
49
|
+
def initialize(context)
|
|
50
|
+
@commands = Nuklear::Buffer.new
|
|
51
|
+
@vertices = Nuklear::Buffer.new
|
|
52
|
+
@vertex_indices = Nuklear::Buffer.new
|
|
53
|
+
@context = context
|
|
54
|
+
@window_size = [640, 480]
|
|
55
|
+
@drawable_size = nil
|
|
56
|
+
@null_texture_handle = 0
|
|
57
|
+
@convert_config = {
|
|
58
|
+
vertex_layout: [
|
|
59
|
+
[:position, :float, Vertex.offsetof('position')],
|
|
60
|
+
[:texcoord, :float, Vertex.offsetof('uv')],
|
|
61
|
+
[:color, :r8g8b8a8, Vertex.offsetof('color')]
|
|
62
|
+
],
|
|
63
|
+
vertex_size: Vertex.size,
|
|
64
|
+
vertex_alignment: Vertex.alignment,
|
|
65
|
+
null: null_texture_handle,
|
|
66
|
+
circle_segment_count: 22,
|
|
67
|
+
curve_segment_count: 22,
|
|
68
|
+
arc_segment_count: 22,
|
|
69
|
+
global_alpha: 1.0,
|
|
70
|
+
shape_aa: true,
|
|
71
|
+
line_aa: true
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def null_texture_handle=(n)
|
|
76
|
+
@null_texture_handle = n
|
|
77
|
+
@convert_config[:null] = n
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def drawable_size
|
|
81
|
+
@drawable_size || window_size
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Called at the start of a render pass. Renderers may wish to override
|
|
85
|
+
# this method to apply once-per-frame state updates. They should call
|
|
86
|
+
# `super` when they are ready to proceed.
|
|
87
|
+
def render
|
|
88
|
+
nk_convert
|
|
89
|
+
nk_draw_foreach { |command| draw(command) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Called for each Nuklear draw command, numerous times per render pass.
|
|
93
|
+
# Renderers should override this method to actually draw something, but
|
|
94
|
+
# keep this method as lightweight as possible.
|
|
95
|
+
#
|
|
96
|
+
# `element_count`: The number of elements to be drawn.
|
|
97
|
+
# `clip_rect`: An array containing the x, y, width and height
|
|
98
|
+
# (in that order) of the region to be drawn to.
|
|
99
|
+
# `texture_handle`: The handle of a texture to be drawn. See
|
|
100
|
+
# #null_texture_handle.
|
|
101
|
+
# `offset`: The number of elements already drawn, not including the
|
|
102
|
+
# current command.
|
|
103
|
+
#
|
|
104
|
+
def draw(cmd)
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Nuklear
|
|
2
|
+
module Style
|
|
3
|
+
class Color
|
|
4
|
+
# defined in C
|
|
5
|
+
# attr_accessor :red, :green, :blue, :alpha
|
|
6
|
+
# attr_accessor :hue, :saturation, :value
|
|
7
|
+
|
|
8
|
+
def initialize(r, g, b, a = 1)
|
|
9
|
+
self.red = r
|
|
10
|
+
self.green = g
|
|
11
|
+
self.blue = b
|
|
12
|
+
self.alpha = a
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.from_bytes(r, g, b, a = 255)
|
|
16
|
+
new(r / 255.0, g / 255.0, b / 255.0, a / 255.0)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def inspect
|
|
20
|
+
"#<#{self.class.name} red=#{red} green=#{green} blue=#{blue} alpha=#{alpha}>"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Nuklear
|
|
2
|
+
module TestCase
|
|
3
|
+
def nuklear
|
|
4
|
+
@nuklear || raise("Nuklear::TestCase requires you to assign a Nuklear::Context to @nuklear during your test setup.")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def tick
|
|
8
|
+
raise "Nuklear::TestCase requires you to override #tick to process window events and to call your Nuklear::Context#tick method."
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def click_button(text)
|
|
12
|
+
els = nuklear.find do |item|
|
|
13
|
+
item.kind_of?(Nuklear::UI::Button) && item.respond_to?(:text) && item.text[text]
|
|
14
|
+
end
|
|
15
|
+
if els.count > 1
|
|
16
|
+
raise "Ambiguous text: #{text} (found #{els.inspect})"
|
|
17
|
+
elsif els.empty?
|
|
18
|
+
raise "Cannot find an element with text: #{text.inspect}"
|
|
19
|
+
else
|
|
20
|
+
els.first.trigger(:clicked)
|
|
21
|
+
end
|
|
22
|
+
tick
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def assert_text(txt)
|
|
26
|
+
refute_empty nuklear.find { |el| el.respond_to?(:text) && el.text[txt] },
|
|
27
|
+
"Expected to find at least one element with text: #{txt.inspect}"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Nuklear
|
|
2
|
+
module UI
|
|
3
|
+
class Base
|
|
4
|
+
include Nuklear::UI::Events
|
|
5
|
+
include Nuklear::UI::Enableable
|
|
6
|
+
|
|
7
|
+
def initialize(enabled: true)
|
|
8
|
+
self.enabled = enabled
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def dsl(&block)
|
|
12
|
+
require 'nuklear/dsl'
|
|
13
|
+
Nuklear::DSL.new(self, &block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
attr_writer :dsl_method_name
|
|
18
|
+
|
|
19
|
+
def dsl_method_name
|
|
20
|
+
# Nukelar::UI::ColorPicker => 'color_picker'
|
|
21
|
+
@dsl_method_name ||= name.split('::').last.gsub(/([A-Z])/) { |a| "_#{a.downcase}" }.sub(/^_/, '')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def descendants
|
|
25
|
+
@descendants ||= []
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def inherited(child)
|
|
29
|
+
descendants << child
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Nuklear
|
|
2
|
+
module UI
|
|
3
|
+
class Button < Nuklear::UI::Base
|
|
4
|
+
include Nuklear::UI::TextAlign
|
|
5
|
+
|
|
6
|
+
attr_accessor :text
|
|
7
|
+
|
|
8
|
+
# A hash which may contain the following options:
|
|
9
|
+
# :normal => a style item, see the classes contained in Nuklear::Style
|
|
10
|
+
# :hover => a style item, see the classes contained in Nuklear::Style
|
|
11
|
+
# :active => a style item, see the classes contained in Nuklear::Style
|
|
12
|
+
# :border_color => an instance of Nuklear::Style::Color
|
|
13
|
+
# :text_background => an instance of Nuklear::Style::Color
|
|
14
|
+
# :text_normal => an instance of Nuklear::Style::Color
|
|
15
|
+
# :text_hover => an instance of Nuklear::Style::Color
|
|
16
|
+
# :text_active => an instance of Nuklear::Style::Color
|
|
17
|
+
# :text_alignment => a set of alignment flags
|
|
18
|
+
# :border => a float
|
|
19
|
+
# :rounding => a float
|
|
20
|
+
# :padding => a vec2 of floats
|
|
21
|
+
# :image_padding => a vec2 of floats
|
|
22
|
+
# :touch_padding => a vec2 of floats
|
|
23
|
+
attr_accessor :style
|
|
24
|
+
|
|
25
|
+
# Whether the button click event will repeat while the button is pressed
|
|
26
|
+
attr_writer :repeat
|
|
27
|
+
|
|
28
|
+
attr_accessor :color
|
|
29
|
+
|
|
30
|
+
# One of: nil, :x, :underscore, :circle_solid, :circle_outline,
|
|
31
|
+
# :rect_solid, :rect_outline, :triangle_up, :triangle_down,
|
|
32
|
+
# :triangle_left, :triangle_right, :plus, :minus or :max
|
|
33
|
+
attr_accessor :symbol
|
|
34
|
+
|
|
35
|
+
attr_accessor :image
|
|
36
|
+
|
|
37
|
+
# nil, or a set of alignment flags
|
|
38
|
+
attr_accessor :align
|
|
39
|
+
|
|
40
|
+
def initialize(text = nil, style: nil, repeat: false, color: nil, symbol: nil, image: nil, align: nil, **options, &block)
|
|
41
|
+
super(**options)
|
|
42
|
+
@text = text
|
|
43
|
+
@style = style
|
|
44
|
+
@repeat = repeat
|
|
45
|
+
@color = color
|
|
46
|
+
@symbol = symbol
|
|
47
|
+
@image = image
|
|
48
|
+
@align = align
|
|
49
|
+
on(:clicked, &block) if block_given?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def repeat?
|
|
53
|
+
@repeat
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def to_command
|
|
57
|
+
[
|
|
58
|
+
:ui_button, {
|
|
59
|
+
repeat: repeat?,
|
|
60
|
+
title: text,
|
|
61
|
+
color: color,
|
|
62
|
+
symbol: symbol,
|
|
63
|
+
image: image,
|
|
64
|
+
style: style,
|
|
65
|
+
alignment: align_as_flags(align)
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def result(result, context)
|
|
71
|
+
if result == 1 then trigger(:clicked)
|
|
72
|
+
else trigger(:released)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|