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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 00d829f1e7f4d4d305a18e1d831df3cd95874224581986977a89fd2eb114da0f
4
+ data.tar.gz: 45da4ef0e277ca42d642919a06c8086952c695a139b45265df6d5b7ceb4d5aaa
5
+ SHA512:
6
+ metadata.gz: baa5798e57b4f1765b4e819ee7dac4db9aa40e172f44fd48c74ff6b6942bc8c0d5afdc55cc137aeb400b4c48f51cd5286000b4b849505e11b94f2de2e8e9ec43
7
+ data.tar.gz: f37d1e63dcb902f2752c21e37d3ceaebccb0a2b5b9d50d615925049010dc2eedf3c726da9edc0687a63ba9ec651ffcd03cbc052cd0ea16c1b38e28275aa9e777
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.bundle
10
+ *.so
11
+ *.o
12
+ *.a
13
+ mkmf.log
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in nuklear.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nuklear (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ minitest (5.15.0)
10
+ opengl-bindings (1.6.12)
11
+ rake (13.0.6)
12
+ rake-compiler (1.1.9)
13
+ rake
14
+ ruby-sdl2 (0.3.5)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ bundler (>= 2.0)
21
+ minitest (>= 5.0)
22
+ nuklear!
23
+ opengl-bindings
24
+ rake (>= 10.0)
25
+ rake-compiler
26
+ ruby-sdl2
27
+
28
+ BUNDLED WITH
29
+ 2.2.3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Colin MacKenzie IV
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # Nuklear
2
+
3
+ Ruby bindings for [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear).
4
+
5
+ Here is the description from the Nuklear project:
6
+
7
+ > This is a minimal-state, immediate-mode graphical user interface toolkit
8
+ > written in ANSI C and licensed under public domain. It was designed as a
9
+ > simple embeddable user interface for application and does not have any
10
+ > dependencies, a default render backend or OS window/input handling but
11
+ > instead provides a highly modular, library-based approach, with simple
12
+ > input state for input and draw commands describing primitive shapes as
13
+ > output. So instead of providing a layered library that tries to abstract
14
+ > over a number of platform and render backends, it focuses only on the actual
15
+ > UI.
16
+
17
+ This project implements a set of Ruby classes which wrap the Nuklear API. It
18
+ also provides two sample renderers (OpenGL 2 and OpenGL 4).
19
+
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'nuklear'
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install nuklear
36
+
37
+
38
+ ## Renderers
39
+
40
+ The base class `Nuklear::Renderer` is essentially a headless renderer. It
41
+ implements all necessary functionality to serve as a renderer for Nuklear,
42
+ except the actual drawing, and is also intended to be subclassed for a custom
43
+ renderer which actually draws something. The two bundled OpenGL renderers
44
+ (`Nuklear::Renderer::OpenGL2` and `Nuklear::Renderer::OpenGL4`) are examples
45
+ of this.
46
+
47
+
48
+ ## API
49
+
50
+ The following examples are to help introduce you to how to use Nuklear, and
51
+ to inform you as to how Nuklear fits into the larger design of a graphical
52
+ application. They are not complete examples. For complete, functional
53
+ examples, see the files in /examples/.
54
+
55
+
56
+ ## Initialization
57
+
58
+ ```ruby
59
+ # Nuklear will load the font files for us, and will generate a font atlas
60
+ # image. Then it will yield the width, height and pixel data of that image
61
+ # to our block. Typically we would use this information to generate a
62
+ # texture for our preferred rendering engine (OpenGL, Vulkan, etc.). Once
63
+ # we have a handle, we pass that handle back to Nuklear as the result of
64
+ # the block. Here we just use `0`. Nuklear will hold on to the handle,
65
+ # and it will be passed back to us as part of draw calls involving the
66
+ #font.
67
+ font = Nuklear::Font.new("arial.ttf", 12) { |w, h, data| 0 }
68
+
69
+ # Once we have our font, we can create a Nuklear context.
70
+ ctx = Nuklear::Context.new(font)
71
+
72
+ # The context requires a renderer. We can pass it an instance of
73
+ # Nuklear::Renderer, but this will not actually draw anything.
74
+ # Nuklear::Renderer is great for unit testing and as a base class for us
75
+ # to actually implement our real renderer on top of. Here, we'll use the
76
+ # bundled OpenGL 2 renderer.
77
+ require 'nuklear/nuklear_renderer_opengl2'
78
+ ctx.renderer = Nuklear::Renderer::OpenGL2.new(ctx)
79
+ ```
80
+
81
+ ### With DSL
82
+
83
+ For convenience, a DSL is provided. It is particularly useful for building
84
+ complex, mostly static interfaces as it removes a lot of the repetition that
85
+ would come from using the primary interface. Here is a trivial example:
86
+
87
+ ```ruby
88
+ ctx.dsl do
89
+ w = window "Hello Nuklear", left: 10, top: 10, width: 100, height: 100 do
90
+ layout_row_dynamic 35, 2
91
+ button "Click me" do
92
+ puts "Ouch!"
93
+ w.close # hide the window
94
+ end
95
+ end
96
+ end
97
+ ```
98
+
99
+ See `/examples/calculator.rb` for a more complete demonstration of the DSL.
100
+
101
+
102
+ ### Without DSL
103
+
104
+ You can opt not to use the DSL, and instantiate the UI widgets directly. This
105
+ is straightforward, but verbose. It can be helpful when you need to
106
+ programmatically build an interface that doesn't need or desire a lot of
107
+ syntactic sugar. For example, the DSL might actively hinder you if you were
108
+ building an interface by parsing a YAML or XML file. Here is how we would
109
+ build the same window as above without use of the DSL:
110
+
111
+ ```ruby
112
+ # create the Nuklear window
113
+ w = Nuklear::UI::Window.new "Hello Nuklear",
114
+ left: 10,
115
+ top: 10,
116
+ width: 100,
117
+ height: 100
118
+
119
+ # Set up the window layout
120
+ w.layout_row_dynamic 35, 2
121
+
122
+ # Add the button to the window
123
+ w << Nuklear::UI::Button.new "Click me" do
124
+ puts "Ouch!"
125
+ w.close # hide the window
126
+ end
127
+
128
+ # Add the window to the context
129
+ ctx << w
130
+ ```
131
+
132
+ See `/examples/hello_nuklear.rb` for a more complete demonstration without the
133
+ DSL.
134
+
135
+
136
+ ### Main Loop
137
+
138
+ Since Nuklear is backend-agnostic, you must do the backend stuff yourself. In
139
+ all of the examples, you'll find that we use SDL2 for the window management
140
+ and event processing, and OpenGL for the actual drawing. You may use whatever
141
+ mechanisms you want, including none. (It's quite useful for unit testing to
142
+ just use the Nuklear::Renderer base class for "drawing" and to
143
+ programmatically deliver only specific window events to Nuklear.)
144
+
145
+ The event processing loop can be a bit verbose, depending on how many events
146
+ you want to respond to, so we'll just show some snippets here. You can find a
147
+ more complete example in `/examples/hello_nuklear.rb`.
148
+
149
+ ```ruby
150
+ # Initialize the viewport (OpenGL)
151
+ glViewport(0, 0, *window.gl_drawable_size)
152
+ glClearColor(0, 0, 0, 0)
153
+ while true
154
+ # New frame: Clear the screen (OpenGL)
155
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
156
+
157
+ # Process window, mouse, keyboard, etc events (SDL2)
158
+ while event = ::SDL2::Event.poll
159
+ case event
160
+ when SDL2::Event::Quit then exit
161
+ # ...
162
+ end
163
+
164
+ # Update the Nuklear context. This will generate/update the command buffer
165
+ # in preparation for rendering, then pass that command buffer to our
166
+ # renderer.
167
+ ctx.tick
168
+
169
+ # Show the rendered frame. (OpenGL)
170
+ window.gl_swap
171
+ end
172
+ ```
173
+
174
+
175
+ ## Development
176
+
177
+ After checking out the repo, run `bin/setup` to install dependencies. Then,
178
+ run `rake test` to run the tests. You can also run `bin/console` for an
179
+ interactive prompt that will allow you to experiment.
180
+
181
+ To install this gem onto your local machine, run `bundle exec rake install`.
182
+ To release a new version, update the version number in `version.rb`, and then
183
+ run `bundle exec rake release`, which will create a git tag for the version,
184
+ push git commits and tags, and push the `.gem` file to
185
+ [rubygems.org](https://rubygems.org).
186
+
187
+
188
+ ## Contributing
189
+
190
+ Bug reports and pull requests are welcome on GitHub at
191
+ https://github.com/[USERNAME]/nuklear.
192
+
193
+ ## License
194
+
195
+ The gem is available as open source under the terms of the
196
+ [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ require "rake/extensiontask"
11
+
12
+ task :build => :compile
13
+
14
+ Rake::ExtensionTask.new("nuklear") do |ext|
15
+ ext.lib_dir = "lib/nuklear"
16
+ end
17
+
18
+ Rake::ExtensionTask.new("nuklear_renderer_opengl2") do |ext|
19
+ ext.lib_dir = "lib/nuklear"
20
+ end
21
+
22
+ Rake::ExtensionTask.new("nuklear_renderer_opengl4") do |ext|
23
+ ext.lib_dir = "lib/nuklear"
24
+ end
25
+
26
+ task :default => [:clobber, :compile, :test]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "nuklear"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
Binary file
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This example is based loosely upon:
4
+ # https://github.com/Immediate-Mode-UI/Nuklear/blob/master/demo/calculator.c
5
+ #
6
+ # This demonstrates using the Nuklear DSL to build and maintain a simple but
7
+ # functional calculator. In order to show you only the most relevant
8
+ # information, much of the set-up code has been moved to /examples/lib/ and
9
+ # this file focuses mainly on the DSL. If you are more interested in the
10
+ # set-up code and event loop, you will find that the files in /examples/lib/
11
+ # are quite similar to what appears in /examples/hello_nuklear.rb.
12
+ #
13
+ require 'bundler/setup'
14
+ require 'nuklear'
15
+ require_relative 'lib/sdl2_init'
16
+ require_relative 'lib/sdl2_input'
17
+ require_relative 'lib/opengl_init'
18
+ require_relative 'lib/opengl_font'
19
+ require_relative 'lib/window'
20
+
21
+ class Calculator
22
+ attr_reader :ctx, :window
23
+
24
+ def initialize(hidden: false)
25
+ @window = Examples::Window.new "Calculator Example", hidden: hidden
26
+ font = Examples::OpenGLFont.new File.expand_path("arial.ttf", __dir__)
27
+ @ctx = Nuklear::Context.new font.nuklear_handle
28
+ @window.nuklear_context = @ctx
29
+
30
+ numbers = '789456123'
31
+ ops = '+-*/'
32
+ operands = [0, 0]
33
+ current = 0
34
+ set = op = nil
35
+
36
+ @ctx.dsl do
37
+ window("Hello Nuklear", left: 10, top: 10, width: 180, height: 250,
38
+ border: true, no_scrollbar: true, movable: true) do
39
+ layout_row_dynamic 35, 1
40
+ label = edit_string text: "0.0", flags: :simple, filter: :float, max_length: 255
41
+
42
+ layout_row_dynamic 35, 4
43
+ update = proc { label.text = '%.2f' % operands[current] }
44
+ solver = proc do
45
+ # operands[0] = operands[0] + operands[1]
46
+ operands[0] = operands[0].send(op, operands[1])
47
+ label.text = '%.2f' % operands[0]
48
+ current = 1
49
+ operands[1] = 0
50
+ set = true
51
+ end
52
+ 16.times do |i|
53
+ if i >= 12 && i < 15
54
+ next if i > 12
55
+ button("C") { operands = [0, 0]; current = 0; op = nil; update.call }
56
+ button("0") { operands[current] *= 10; update.call }
57
+ button("=") { solver.call; op = nil }
58
+ elsif (i + 1) % 4 > 0
59
+ n = numbers[(i/4)*3+i%4]
60
+ button(n) do
61
+ operands[current] = operands[current] * 10 + n.to_i
62
+ set = nil
63
+ update.call
64
+ end
65
+ else
66
+ n = ops[i/4]
67
+ button(n) do
68
+ if !set
69
+ if current != 1
70
+ current = 1
71
+ update.call
72
+ else
73
+ solver.call
74
+ end
75
+ end
76
+ op = ops[i/4]
77
+ set = true
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def tick
86
+ @window.frame do
87
+ @ctx.tick
88
+ end
89
+ end
90
+
91
+ def close
92
+ @window.close
93
+ end
94
+ end
95
+
96
+ if $0 == __FILE__
97
+ calculator = Calculator.new
98
+ while true
99
+ # process window events and render any display changes
100
+ calculator.tick
101
+ end
102
+ end
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This example is completely self-contained (the files in /examples/lib/ are
4
+ # not used), so it makes a good "holistic" reference. It's a little on the
5
+ # large side, mainly because of the SDL2 event loop as interesting events have
6
+ # to be delegated into Nuklear so that, for example, button clicks actually
7
+ # do something.
8
+ #
9
+ # This example also eschews the Nuklear DSL, instead preferring to instantiate
10
+ # the UI widgets directly. Essentially, this shows you what is happening
11
+ # within the DSL, and it can be a useful reference if you're in a situation
12
+ # where the DSL is cumbersome to use. That said, it's not nearly as pretty
13
+ # or intuitive as using the DSL would be.
14
+ #
15
+ require 'bundler/setup'
16
+ require 'sdl2'
17
+ require 'nuklear'
18
+ require 'opengl'
19
+ include OpenGL
20
+ OpenGL.load_lib()
21
+
22
+ module SDL2::Window::Flags
23
+ # Shim: Older versions of SDL2 for Ruby didn't define this flag.
24
+ ALLOW_HIGHDPI = 0x00002000 unless defined?(SDL2::Window::Flags::ALLOW_HIGHDPI)
25
+ end
26
+
27
+ # Initialize SDL2 and OpenGL.
28
+ SDL2.init(SDL2::INIT_EVERYTHING)
29
+ SDL2::GL.set_attribute(SDL2::GL::ACCELERATED_VISUAL, 1)
30
+ window = SDL2::Window.create "Nuklear", 0, 0, 640, 480,
31
+ SDL2::Window::Flags::OPENGL |
32
+ SDL2::Window::Flags::ALLOW_HIGHDPI |
33
+ SDL2::Window::Flags::RESIZABLE
34
+ @gl = SDL2::GL::Context.create(window)
35
+
36
+ # When Nuklear loads the font file it will yield to us the width, height
37
+ # and baked font atlas image data. We must then tell OpenGL to load that
38
+ # image data into a texture ID, and then pass the OpenGL texture ID back into
39
+ # Nuklear for later reference.
40
+ font = Nuklear::Font.new(File.expand_path("arial.ttf", __dir__), 14) do |w, h, data|
41
+ # give the image data to OpenGL
42
+ tex_names_buf = ' ' * 8
43
+ glGenTextures(1, tex_names_buf)
44
+ texture_id = tex_names_buf.unpack('L1')[0]
45
+ glBindTexture(GL_TEXTURE_2D, texture_id)
46
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
47
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
48
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
49
+ # give the GL texture ID to Nuklear
50
+ texture_id
51
+ end
52
+
53
+ ctx = Nuklear::Context.new(font)
54
+
55
+ # We'll use the OpenGL 2 renderer for Nuklear. Notice that we must tell the
56
+ # renderer the size of the window and the size of the drawing surface, which
57
+ # aren't always the same thing.
58
+ require 'nuklear/nuklear_renderer_opengl2'
59
+ ctx.renderer = Nuklear::Renderer::OpenGL2.new(ctx)
60
+ ctx.renderer.window_size = window.size
61
+ ctx.renderer.drawable_size = window.gl_drawable_size
62
+
63
+ # We can now build our Nuklear UI. Let's create a window, then add a few
64
+ # labels and a button to it.
65
+ @window = Nuklear::UI::Window.new("Hello Nuklear",
66
+ left: 60, top: 60, width: 300, height: 200,
67
+ border: true, scalable: true, movable: true, minimizable: true)
68
+ @window.layout_row_dynamic 35, 2
69
+ @window << Nuklear::UI::Label.new("This is a label")
70
+ @window << Nuklear::UI::Button.new("This is a button")
71
+ @window << Nuklear::UI::Label.new("Frame number:")
72
+ @window << @frame_num_label = Nuklear::UI::Label.new("0")
73
+ # Let's also add a large, empty container to the window. This forces Nuklear
74
+ # to add a scrollbar to the window.
75
+ @window.layout_row_dynamic 200, 2
76
+ container = Nuklear::UI::Group.new
77
+ @window << container
78
+
79
+ # Finally, add the window to the context so that Nuklear will render it. We
80
+ # can add any number of windows.
81
+ ctx << @window
82
+
83
+ # Now for the main event loop. This loop is almost entirely dedicated to event
84
+ # processing. Below the event processing, we'll deal with Nuklear.
85
+ @frame_count = 0
86
+ glViewport(0, 0, *window.gl_drawable_size)
87
+ glClearColor(0, 0, 0, 0)
88
+ @last_tick_time = Time.now
89
+ while true
90
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
91
+
92
+ while event = ::SDL2::Event.poll
93
+ case event
94
+ # TODO touch events
95
+ # when SDL2::Event::FingerMotion
96
+ # when SDL2::Event::FingerDown
97
+ # when SDL2::Event::FingerUp
98
+ when ::SDL2::Event::TextInput then ctx.trigger(:glyph, event.text)
99
+ when ::SDL2::Event::MouseMotion then ctx.trigger(:motion, event.x, event.y, event.xrel, event.yrel)
100
+ when ::SDL2::Event::MouseWheel then ctx.trigger(:scroll, event.x, event.y)
101
+ when ::SDL2::Event::MouseButtonDown, ::SDL2::Event::MouseButtonUp
102
+ is_down = event.kind_of?(::SDL2::Event::MouseButtonDown)
103
+ if event.button == 1 and event.clicks > 1
104
+ ctx.trigger(:button, :double, event.x, event.y, is_down)
105
+ else
106
+ case event.button
107
+ # SDL_BUTTON_LEFT seems to be not defined
108
+ when 1 then ctx.trigger(:button, :left, event.x, event.y, is_down)
109
+ when 2 then ctx.trigger(:button, :middle, event.x, event.y, is_down)
110
+ when 3 then ctx.trigger(:button, :right, event.x, event.y, is_down)
111
+ end
112
+ end
113
+ when ::SDL2::Event::Window
114
+ case event.event
115
+ when ::SDL2::Event::Window::FOCUS_GAINED then @focused = true
116
+ when ::SDL2::Event::Window::FOCUS_LOST then @focused = false
117
+ end
118
+ when ::SDL2::Event::KeyDown, ::SDL2::Event::KeyUp
119
+ is_down = event.kind_of?(::SDL2::Event::KeyDown)
120
+ case event.sym
121
+ when ::SDL2::Key::LSHIFT, ::SDL2::Key::RSHIFT then ctx.trigger(:key, :shift, is_down)
122
+ when ::SDL2::Key::DELETE then ctx.trigger(:key, :del, is_down)
123
+ when ::SDL2::Key::RETURN then ctx.trigger(:key, :enter, is_down)
124
+ when ::SDL2::Key::TAB then ctx.trigger(:key, :tab, is_down)
125
+ when ::SDL2::Key::BACKSPACE then ctx.trigger(:key, :backspace, is_down)
126
+ when ::SDL2::Key::HOME then ctx.trigger(:key, :text_start, is_down)
127
+ ctx.trigger(:key, :scroll_start, is_down)
128
+ when ::SDL2::Key::END then ctx.trigger(:key, :text_end, is_down)
129
+ ctx.trigger(:key, :scroll_end, is_down)
130
+ when ::SDL2::Key::PAGEDOWN then ctx.trigger(:key, :scroll_down, is_down)
131
+ when ::SDL2::Key::PAGEUP then ctx.trigger(:key, :scroll_up, is_down)
132
+ when ::SDL2::Key::Z then ctx.trigger(:key, :text_undo, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
133
+ when ::SDL2::Key::R then ctx.trigger(:key, :text_redo, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
134
+ when ::SDL2::Key::C then ctx.trigger(:key, :copy, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
135
+ when ::SDL2::Key::V then ctx.trigger(:key, :paste, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
136
+ when ::SDL2::Key::X then ctx.trigger(:key, :cut, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
137
+ when ::SDL2::Key::B then ctx.trigger(:key, :text_line_start, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
138
+ when ::SDL2::Key::E then ctx.trigger(:key, :text_line_end, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
139
+ when ::SDL2::Key::UP then ctx.trigger(:key, :up, is_down)
140
+ when ::SDL2::Key::DOWN then ctx.trigger(:key, :down, is_down)
141
+ when ::SDL2::Key::LEFT
142
+ if event.mod & ::SDL2::Key::Mod::CTRL > 0 then ctx.trigger(:key, :text_word_left, is_down)
143
+ else ctx.trigger(:key, :left, is_down)
144
+ end
145
+ when ::SDL2::Key::RIGHT
146
+ if event.mod & ::SDL2::Key::Mod::CTRL > 0 then ctx.trigger(:key, :text_word_right, is_down)
147
+ else ctx.trigger(:key, :right, is_down)
148
+ end
149
+ end
150
+
151
+ when SDL2::Event::Quit then exit
152
+ when SDL2::Event::KeyDown
153
+ case event.sym
154
+ when SDL2::Key::C
155
+ if (event.mod & SDL2::Key::Mod::CTRL) > 0
156
+ exit
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ # Track the number of frames and calculate the amount of time that has
163
+ # elapsed between the last frame and this one.
164
+ @frame_count += 1
165
+ time = Time.now
166
+ delta ||= begin
167
+ delta = time - @last_tick_time
168
+ end
169
+ @last_tick_time = time
170
+
171
+ # Update the frame counter label. The next time Nuklear renders it, the
172
+ # label will contain the updated text.
173
+ @frame_num_label.text = @frame_count.to_s
174
+
175
+ # Update the Nuklear context. This will generate/update the command buffer
176
+ # in preparation for rendering, then pass that command buffer to our
177
+ # renderer.
178
+ ctx.tick
179
+
180
+ # Show the rendered frame.
181
+ window.gl_swap
182
+ end
@@ -0,0 +1,32 @@
1
+ # This class facilitates rendering text with Nuklear and presenting it using
2
+ # OpenGL. It is part of the nuklear-ruby examples.
3
+ module Examples
4
+ class OpenGLFont
5
+ attr_reader :path
6
+
7
+ def initialize(path, size = 12)
8
+ @path = path
9
+ @size = size
10
+ @texture_id = nil
11
+ @nuklear_handle = nil
12
+ end
13
+
14
+ def texture_id
15
+ @texture_id ||= begin
16
+ tex_names_buf = ' ' * 8
17
+ glGenTextures(1, tex_names_buf)
18
+ tex_names_buf.unpack('L1')[0]
19
+ end
20
+ end
21
+
22
+ def nuklear_handle
23
+ @nuklear_handle ||= Nuklear::Font.new(path, @size) do |w, h, data|
24
+ glBindTexture(GL_TEXTURE_2D, texture_id)
25
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
26
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
27
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
28
+ texture_id
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,4 @@
1
+ require 'opengl'
2
+ include OpenGL
3
+ OpenGL.load_lib()
4
+ SDL2::GL.set_attribute(SDL2::GL::ACCELERATED_VISUAL, 1)
@@ -0,0 +1,6 @@
1
+ require 'sdl2'
2
+ SDL2.init(SDL2::INIT_EVERYTHING)
3
+
4
+ module SDL2::Window::Flags
5
+ ALLOW_HIGHDPI = 0x00002000 unless defined?(SDL2::Window::Flags::ALLOW_HIGHDPI)
6
+ end