nuklear 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|