nuklear 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +29 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +196 -0
  8. data/Rakefile +26 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/examples/arial.ttf +0 -0
  12. data/examples/calculator.rb +102 -0
  13. data/examples/hello_nuklear.rb +182 -0
  14. data/examples/lib/opengl_font.rb +32 -0
  15. data/examples/lib/opengl_init.rb +4 -0
  16. data/examples/lib/sdl2_init.rb +6 -0
  17. data/examples/lib/sdl2_input.rb +81 -0
  18. data/examples/lib/window.rb +47 -0
  19. data/ext/freetype/extconf.rb +26 -0
  20. data/ext/nuklear/extconf.rb +14 -0
  21. data/ext/nuklear/nkrb.c +79 -0
  22. data/ext/nuklear/nkrb.h +89 -0
  23. data/ext/nuklear/nkrb_buffer.c +80 -0
  24. data/ext/nuklear/nkrb_context.c +241 -0
  25. data/ext/nuklear/nkrb_font.c +80 -0
  26. data/ext/nuklear/nkrb_renderer.c +114 -0
  27. data/ext/nuklear/nkrb_style.c +61 -0
  28. data/ext/nuklear/nkrb_style_color.c +126 -0
  29. data/ext/nuklear/nkrb_style_image.c +32 -0
  30. data/ext/nuklear/nkrb_ui.c +32 -0
  31. data/ext/nuklear/nkrb_ui_builder.c +29 -0
  32. data/ext/nuklear/nkrb_ui_button.c +55 -0
  33. data/ext/nuklear/nkrb_ui_color_picker.c +20 -0
  34. data/ext/nuklear/nkrb_ui_combo.c +73 -0
  35. data/ext/nuklear/nkrb_ui_container.c +7 -0
  36. data/ext/nuklear/nkrb_ui_edit_string.c +38 -0
  37. data/ext/nuklear/nkrb_ui_group.c +27 -0
  38. data/ext/nuklear/nkrb_ui_label.c +30 -0
  39. data/ext/nuklear/nkrb_ui_layout.c +125 -0
  40. data/ext/nuklear/nkrb_ui_menu.c +49 -0
  41. data/ext/nuklear/nkrb_ui_menu_item.c +30 -0
  42. data/ext/nuklear/nkrb_ui_menubar.c +18 -0
  43. data/ext/nuklear/nkrb_ui_popup.c +24 -0
  44. data/ext/nuklear/nkrb_ui_progress.c +19 -0
  45. data/ext/nuklear/nkrb_ui_property.c +20 -0
  46. data/ext/nuklear/nkrb_ui_selectables.c +53 -0
  47. data/ext/nuklear/nkrb_ui_slider.c +19 -0
  48. data/ext/nuklear/nkrb_ui_tree.c +29 -0
  49. data/ext/nuklear/nkrb_ui_widget.c +7 -0
  50. data/ext/nuklear/nkrb_ui_window.c +43 -0
  51. data/ext/nuklear/nuklear.h +23378 -0
  52. data/ext/nuklear_renderer_opengl2/KHR/khrplatform.h +285 -0
  53. data/ext/nuklear_renderer_opengl2/extconf.rb +13 -0
  54. data/ext/nuklear_renderer_opengl2/glad.c +1432 -0
  55. data/ext/nuklear_renderer_opengl2/glad.h +2747 -0
  56. data/ext/nuklear_renderer_opengl2/nuklear_renderer_opengl2.c +197 -0
  57. data/ext/nuklear_renderer_opengl4/KHR/khrplatform.h +285 -0
  58. data/ext/nuklear_renderer_opengl4/extconf.rb +13 -0
  59. data/ext/nuklear_renderer_opengl4/glad.c +1782 -0
  60. data/ext/nuklear_renderer_opengl4/glad.h +3687 -0
  61. data/ext/nuklear_renderer_opengl4/nuklear_renderer_opengl4.c +255 -0
  62. data/lib/nuklear/context.rb +49 -0
  63. data/lib/nuklear/dsl.rb +46 -0
  64. data/lib/nuklear/event_buffer.rb +23 -0
  65. data/lib/nuklear/renderer/opengl24.rb +13 -0
  66. data/lib/nuklear/renderer.rb +108 -0
  67. data/lib/nuklear/style/color.rb +24 -0
  68. data/lib/nuklear/style/image.rb +9 -0
  69. data/lib/nuklear/style.rb +8 -0
  70. data/lib/nuklear/test_case.rb +30 -0
  71. data/lib/nuklear/ui/base.rb +34 -0
  72. data/lib/nuklear/ui/button.rb +77 -0
  73. data/lib/nuklear/ui/checkbox.rb +39 -0
  74. data/lib/nuklear/ui/col.rb +21 -0
  75. data/lib/nuklear/ui/color_picker.rb +31 -0
  76. data/lib/nuklear/ui/combo_box.rb +42 -0
  77. data/lib/nuklear/ui/container.rb +80 -0
  78. data/lib/nuklear/ui/edit_string.rb +48 -0
  79. data/lib/nuklear/ui/enableable.rb +29 -0
  80. data/lib/nuklear/ui/events.rb +23 -0
  81. data/lib/nuklear/ui/group.rb +31 -0
  82. data/lib/nuklear/ui/label.rb +21 -0
  83. data/lib/nuklear/ui/menu.rb +43 -0
  84. data/lib/nuklear/ui/menu_bar.rb +19 -0
  85. data/lib/nuklear/ui/menu_item.rb +34 -0
  86. data/lib/nuklear/ui/option.rb +17 -0
  87. data/lib/nuklear/ui/option_group.rb +22 -0
  88. data/lib/nuklear/ui/popup.rb +37 -0
  89. data/lib/nuklear/ui/progress.rb +33 -0
  90. data/lib/nuklear/ui/property.rb +28 -0
  91. data/lib/nuklear/ui/row.rb +28 -0
  92. data/lib/nuklear/ui/select_list.rb +31 -0
  93. data/lib/nuklear/ui/selectable.rb +21 -0
  94. data/lib/nuklear/ui/slider.rb +26 -0
  95. data/lib/nuklear/ui/text_align.rb +14 -0
  96. data/lib/nuklear/ui/tree.rb +62 -0
  97. data/lib/nuklear/ui/window.rb +175 -0
  98. data/lib/nuklear/ui.rb +33 -0
  99. data/lib/nuklear/version.rb +3 -0
  100. data/lib/nuklear.rb +26 -0
  101. data/nuklear.gemspec +41 -0
  102. 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
@@ -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,9 @@
1
+ module Nuklear
2
+ module Style
3
+ class Image
4
+ def initialize(id)
5
+ self.id = id
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Nuklear
2
+ module UI
3
+ module Style
4
+ require 'nuklear/style/color'
5
+ require 'nuklear/style/image'
6
+ end
7
+ end
8
+ 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