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.
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