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