hokusai-zero 0.2.6 → 0.2.7

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -1
  3. data/Gemfile.lock +0 -2
  4. data/README.md +1 -1
  5. data/ast/src/core/ast.c +3 -11
  6. data/ast/src/core/hml.c +212 -40
  7. data/ast/src/core/hml.h +1 -0
  8. data/ast/src/core/input.h +0 -1
  9. data/ast/src/core/log.c +87 -0
  10. data/ast/src/core/log.h +41 -0
  11. data/ast/src/core/util.c +23 -23
  12. data/ast/src/core/util.h +7 -7
  13. data/ast/test/parser.c +1 -0
  14. data/ext/extconf.rb +6 -6
  15. data/hokusai.gemspec +1 -2
  16. data/ui/examples/drag.rb +154 -0
  17. data/ui/examples/embedded.rb +58 -0
  18. data/ui/examples/forum/file.rb +1 -1
  19. data/ui/examples/forum/post.rb +0 -1
  20. data/ui/examples/forum.rb +7 -7
  21. data/ui/examples/game.rb +143 -0
  22. data/ui/examples/keyboard.rb +47 -0
  23. data/ui/examples/overlay.rb +233 -0
  24. data/ui/examples/provider.rb +56 -0
  25. data/ui/examples/shader/test.rb +155 -0
  26. data/ui/examples/shader.rb +100 -0
  27. data/ui/examples/spreadsheet.rb +12 -11
  28. data/ui/examples/wiki.rb +82 -0
  29. data/ui/lib/lib_hokusai.rb +43 -24
  30. data/ui/spec/hokusai/e2e/keyboard_spec.rb +52 -0
  31. data/ui/spec/spec_helper.rb +1 -1
  32. data/ui/src/hokusai/assets/arrow-down-line.png +0 -0
  33. data/ui/src/hokusai/assets/arrow-down-wide-line.png +0 -0
  34. data/ui/src/hokusai/assets/icons/outline/arrow-big-up.svg +19 -0
  35. data/ui/src/hokusai/assets/icons/outline/backspace.svg +20 -0
  36. data/ui/src/hokusai/automation/driver_commands/base.rb +2 -8
  37. data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +3 -6
  38. data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +12 -5
  39. data/ui/src/hokusai/automation/server.rb +2 -3
  40. data/ui/src/hokusai/backends/raylib/config.rb +2 -1
  41. data/ui/src/hokusai/backends/raylib/font.rb +24 -3
  42. data/ui/src/hokusai/backends/raylib.rb +167 -36
  43. data/ui/src/hokusai/backends/sdl2/config.rb +9 -6
  44. data/ui/src/hokusai/backends/sdl2/font.rb +3 -1
  45. data/ui/src/hokusai/backends/sdl2.rb +188 -93
  46. data/ui/src/hokusai/blocks/color_picker.rb +1080 -0
  47. data/ui/src/hokusai/blocks/input.rb +2 -2
  48. data/ui/src/hokusai/blocks/keyboard.rb +249 -0
  49. data/ui/src/hokusai/blocks/shader_begin.rb +22 -0
  50. data/ui/src/hokusai/blocks/shader_end.rb +12 -0
  51. data/ui/src/hokusai/blocks/slider.rb +139 -0
  52. data/ui/src/hokusai/blocks/texture.rb +23 -0
  53. data/ui/src/hokusai/commands/rect.rb +12 -3
  54. data/ui/src/hokusai/commands/shader.rb +33 -0
  55. data/ui/src/hokusai/commands/texture.rb +26 -0
  56. data/ui/src/hokusai/commands.rb +22 -0
  57. data/ui/src/hokusai/event.rb +2 -1
  58. data/ui/src/hokusai/events/keyboard.rb +11 -18
  59. data/ui/src/hokusai/events/mouse.rb +10 -8
  60. data/ui/src/hokusai/events/touch.rb +62 -0
  61. data/ui/src/hokusai/meta.rb +9 -4
  62. data/ui/src/hokusai/mounting/loop_entry.rb +1 -1
  63. data/ui/src/hokusai/mounting/update_entry.rb +7 -6
  64. data/ui/src/hokusai/painter.rb +31 -8
  65. data/ui/src/hokusai/types/display.rb +151 -0
  66. data/ui/src/hokusai/types/keyboard.rb +168 -0
  67. data/ui/src/hokusai/types/mouse.rb +36 -0
  68. data/ui/src/hokusai/types/primitives.rb +56 -0
  69. data/ui/src/hokusai/types/touch.rb +181 -0
  70. data/ui/src/hokusai/types.rb +20 -244
  71. data/ui/src/hokusai/util/wrap_stream.rb +193 -0
  72. data/ui/src/hokusai.rb +61 -35
  73. data/xmake.lua +2 -1
  74. metadata +34 -22
  75. data/ui/src/hokusai/assets/chevron-down.svg +0 -1
@@ -5,6 +5,34 @@ require 'memory_profiler'
5
5
 
6
6
  module Hokusai::Backends
7
7
  class RaylibBackend
8
+
9
+ SDF_SHADER = <<~EOF
10
+ #version 100
11
+
12
+ precision mediump float;
13
+
14
+ // Input vertex attributes (from vertex shader)
15
+ varying vec2 fragTexCoord;
16
+ varying vec4 fragColor;
17
+
18
+ // Input uniform values
19
+ uniform sampler2D texture0;
20
+ uniform vec4 colDiffuse;
21
+
22
+ // NOTE: Add your custom variables here
23
+ const float smoothing = 1.0/32.0;
24
+
25
+ void main()
26
+ {
27
+ // Texel color fetching from texture sampler
28
+ // NOTE: Calculate alpha using signed distance field (SDF)
29
+ float distance = texture2D(texture0, fragTexCoord).a;
30
+ float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
31
+
32
+ // Calculate final fragment color
33
+ gl_FragColor = vec4(fragColor.rgb, fragColor.a*alpha);
34
+ }
35
+ EOF
8
36
 
9
37
  RAYLIB_PATH = ENV["RAYLIB_PATH"] || begin
10
38
  path = "#{__dir__}/../../../../vendor/lib"
@@ -28,6 +56,10 @@ module Hokusai::Backends
28
56
  @images ||= {}
29
57
  end
30
58
 
59
+ def self.shaders
60
+ @shaders ||= {}
61
+ end
62
+
31
63
  def self.stopped?
32
64
  @stop = false if @stop.nil?
33
65
 
@@ -69,8 +101,8 @@ module Hokusai::Backends
69
101
  @hml_vec2
70
102
  end
71
103
 
72
- def color(hc)
73
- if @raylib_color.nil?
104
+ def color(hc, fresh = false)
105
+ if @raylib_color.nil? || fresh
74
106
  @raylib_color = Raylib::Color.from_u8(hc.red, hc.green, hc.blue, hc.alpha)
75
107
  else
76
108
  @raylib_color[:r] = hc.red
@@ -109,31 +141,67 @@ module Hokusai::Backends
109
141
  end
110
142
 
111
143
  def process_input(input)
112
- raylib_mouse_pos = Raylib.GetMousePosition
113
- raylib_mouse_delta = Raylib.GetMouseDelta
114
- LibHokusai.hoku_input_mouse_set_scroll(input.raw, Raylib.GetMouseWheelMove)
115
- LibHokusai.hoku_input_set_mouse_position(input.raw, hml_vec2(raylib_mouse_pos.x, raylib_mouse_pos.y))
116
-
117
- input.raw[:mouse][:delta][:x] = raylib_mouse_delta.x
118
- input.raw[:mouse][:delta][:y] = raylib_mouse_delta.y
144
+ if !config.touch
145
+ raylib_mouse_pos = Raylib.GetMousePosition
146
+ raylib_mouse_delta = Raylib.GetMouseDelta
147
+
148
+ input.mouse.pos.x = raylib_mouse_pos.x
149
+ input.mouse.pos.y = raylib_mouse_pos.y
150
+ input.mouse.delta.x = raylib_mouse_delta.x
151
+ input.mouse.delta.y = raylib_mouse_delta.y
152
+ input.mouse.scroll = Raylib.GetMouseWheelMove
153
+ end
119
154
 
120
- [0,1,2].each do |button_id|
121
- clicked = Raylib.IsMouseButtonPressed(button_id)
122
- down = Raylib.IsMouseButtonDown(button_id)
123
- released = Raylib.IsMouseButtonReleased(button_id)
124
- up = Raylib.IsMouseButtonUp(button_id)
155
+ if config.touch
156
+ count = Raylib.GetTouchPointCount
157
+ if count > 0
158
+ vec = Raylib.GetTouchPosition(0)
159
+ unless vec.x.zero? && vec.y.zero?
160
+ input.touch.record(0, vec.x, vec.y)
161
+ end
162
+ else
163
+ input.touch.clear
164
+ end
165
+ else
166
+ {left: 0, middle: 1, right: 2}.each do |key, button_id|
125
167
 
126
- button = mouse_button(clicked: clicked, down: down, released: released, up: up)
127
- LibHokusai.hoku_input_mouse_set_button(input.raw, button, button_id)
168
+ button = input.mouse.public_send(key)
169
+ button.clicked = Raylib.IsMouseButtonPressed(button_id)
170
+ button.down = Raylib.IsMouseButtonDown(button_id)
171
+ button.released = Raylib.IsMouseButtonReleased(button_id)
172
+ button.up = Raylib.IsMouseButtonUp(button_id)
173
+ end
128
174
  end
129
175
 
130
- LibHokusai.hoku_input_keyboard_start(input.raw)
176
+ if config.touch
177
+ if input.touch.touching?
178
+ token = input.touch.token
131
179
 
132
- Keys.each do |(hoku_key, raylib_key)|
133
- LibHokusai.hoku_input_keyboard_set_key(input.raw, hoku_key, Raylib.IsKeyDown(raylib_key))
180
+ input.mouse.pos.x = token[:x]
181
+ input.mouse.pos.y = token[:y]
182
+ end
183
+
184
+ # translate taps to clicks
185
+ if input.touch.tapped?
186
+ input.mouse.left.clicked = true
187
+ input.mouse.left.down = true
188
+ input.mouse.left.released = false
189
+ input.mouse.left.up = false
190
+ else
191
+ input.mouse.left.clicked = true
192
+ input.mouse.left.down = true
193
+ input.mouse.left.released = false
194
+ input.mouse.left.up = false
195
+ end
134
196
  end
135
197
 
136
- LibHokusai.hoku_input_keyboard_stop(input.raw)
198
+ if !input.keyboard_override
199
+ input.keyboard.reset
200
+
201
+ Keys.each do |(hoku_key, raylib_key)|
202
+ input.keyboard.set(hoku_key, Raylib.IsKeyDown(raylib_key))
203
+ end
204
+ end
137
205
  end
138
206
 
139
207
  def self.run(app)
@@ -149,7 +217,6 @@ module Hokusai::Backends
149
217
  self.class.reset
150
218
 
151
219
  Raylib.load_lib(RAYLIB_PATH)
152
-
153
220
  resize = false
154
221
  initial = true
155
222
  width = config.width
@@ -157,11 +224,8 @@ module Hokusai::Backends
157
224
 
158
225
  register_command_handlers
159
226
 
160
- ptr = FFI::MemoryPointer.new :pointer
161
- LibHokusai.hoku_input_init(ptr)
162
- raw = LibHokusai::HmlInput.new(ptr.get_pointer(0))
163
- input = Hokusai::Input.new(raw)
164
- ptr.free
227
+ input = Hokusai::Input.new
228
+ input.support_touch! if config.touch
165
229
 
166
230
  Raylib.SetConfigFlags(config.config_flags)
167
231
  Raylib.InitWindow(config.width, config.height, config.title)
@@ -215,7 +279,7 @@ module Hokusai::Backends
215
279
  block.update
216
280
  block.public_send(:after_updated) if block.respond_to?(:after_updated)
217
281
 
218
- canvas.reset(nil, nil, width.to_f, height.to_f)
282
+ canvas.reset(0.0, 0.0, width.to_f, height.to_f)
219
283
 
220
284
  Raylib.BeginDrawing
221
285
  Raylib.ClearBackground(config.background)
@@ -239,7 +303,6 @@ module Hokusai::Backends
239
303
  Raylib.DrawFPS(10, 10) if ENV["PROFILE"] || ENV["FPS"]
240
304
  Raylib.EndDrawing
241
305
 
242
-
243
306
  break if self.class.stopped?
244
307
  end
245
308
 
@@ -251,7 +314,9 @@ module Hokusai::Backends
251
314
  Raylib.UnloadTexture(texture)
252
315
  end
253
316
 
254
- LibHokusai.hoku_input_free(input.raw)
317
+ self.class.shaders.each do |k, shader|
318
+ Raylib.UnloadShader(shader)
319
+ end
255
320
 
256
321
  if ENV["PROFILE"]
257
322
  report = MemoryProfiler.stop
@@ -263,6 +328,26 @@ module Hokusai::Backends
263
328
  config.automation_driver&.stop
264
329
  end
265
330
 
331
+ def shader_value(value, type)
332
+ case type
333
+ when Hokusai::SHADER_UNIFORM_FLOAT
334
+ ptr = FFI::MemoryPointer.new(:float)
335
+ ptr.write_float(value)
336
+ ptr
337
+ when Hokusai::SHADER_UNIFORM_INT
338
+ ptr = FFI::MemoryPointer.new(:int)
339
+ ptr.write_int(value)
340
+ ptr
341
+ when Hokusai::SHADER_UNIFORM_IVEC2, Hokusai::SHADER_UNIFORM_UIVEC2, Hokusai::SHADER_UNIFORM_VEC2
342
+ Raylib::Vector2.create(*value)
343
+ when Hokusai::SHADER_UNIFORM_VEC3, Hokusai::SHADER_UNIFORM_IVEC3, Hokusai::SHADER_UNIFORM_UIVEC3
344
+ Raylib::Vector3.create(*value)
345
+ when Hokusai::SHADER_UNIFORM_VEC4, Hokusai::SHADER_UNIFORM_UIVEC4, Hokusai::SHADER_UNIFORM_IVEC4
346
+ Raylib::Vector4.create(*value)
347
+ end
348
+ end
349
+
350
+
266
351
  def inside_scissor(x, y, h = 0)
267
352
  return true if @scissor.nil?
268
353
 
@@ -282,11 +367,17 @@ module Hokusai::Backends
282
367
  ibeam: Raylib::MOUSE_CURSOR_IBEAM,
283
368
  crosshair: Raylib::MOUSE_CURSOR_CROSSHAIR,
284
369
  pointer: Raylib::MOUSE_CURSOR_POINTING_HAND,
370
+ none: -1,
285
371
  }[type]
286
372
 
287
373
  raise Hokusai::Error.new("Cursor #{type} not recognized") if raylib_type.nil?
288
374
 
289
- Raylib::SetMouseCursor(raylib_type)
375
+ if raylib_type == -1
376
+ Raylib.HideCursor
377
+ else
378
+ Raylib.ShowCursor
379
+ Raylib::SetMouseCursor(raylib_type)
380
+ end
290
381
  end
291
382
 
292
383
  Hokusai.on_set_mouse_position do |mouse|
@@ -319,6 +410,38 @@ module Hokusai::Backends
319
410
  inside_scissor(canvas.x, canvas.y, canvas.height)
320
411
  end
321
412
 
413
+ Hokusai::Commands::ShaderBegin.on_draw do |command|
414
+ self.class.shaders[command.hash] ||= Raylib.LoadShaderFromMemory(command.vertex_shader, command.fragment_shader)
415
+
416
+ unless command.uniforms.empty?
417
+ command.uniforms.each do |key, value|
418
+ location = Raylib.GetShaderLocation(self.class.shaders[command.hash], key.to_s)
419
+
420
+ ptr = shader_value(value[0], value[1])
421
+ Raylib.SetShaderValue(self.class.shaders[command.hash], location, ptr, value[1])
422
+ ptr.free if ptr.is_a?(FFI::MemoryPointer)
423
+ end
424
+ end
425
+
426
+ Raylib.BeginShaderMode(self.class.shaders[command.hash])
427
+
428
+ @shader = self.class.shaders[command.hash]
429
+ end
430
+
431
+ Hokusai::Commands::ShaderEnd.on_draw do |_|
432
+ Raylib.EndShaderMode
433
+
434
+ @shader = nil
435
+ end
436
+
437
+ Hokusai::Commands::Texture.on_draw do |command|
438
+ self.class.images[command.hash] ||= begin
439
+ image = Raylib.GenImageColor(command.width, command.height, Raylib::BLANK)
440
+ Raylib.LoadTextureFromImage(image)
441
+ end
442
+ Raylib.DrawTexture(self.class.images[command.hash], command.x, command.y, Raylib::WHITE)
443
+ end
444
+
322
445
  Hokusai::Commands::ScissorBegin.on_draw do |command|
323
446
  Raylib.BeginScissorMode(command.x, command.y, command.width, command.height)
324
447
  @scissor = [command.x, command.y, command.width, command.height]
@@ -384,9 +507,9 @@ module Hokusai::Backends
384
507
  next unless inside_scissor(command.x, command.y, command.size)
385
508
 
386
509
  active_name = Hokusai.fonts.active_font_name
387
- font = Hokusai.fonts.active
510
+ font_name = command.font.nil? ? active_name : command.font
388
511
 
389
- Hokusai.fonts.activate command.font.nil? ? active_name : command.font
512
+ Hokusai.fonts.activate font_name
390
513
  font = Hokusai.fonts.active
391
514
 
392
515
  c = color(command.color)
@@ -394,9 +517,16 @@ module Hokusai::Backends
394
517
  y = command.y + command.padding.t
395
518
 
396
519
  if fnt = font
397
- # content = FFI::MemoryPointer.from_string(command.content)
520
+ if fnt.sdf
521
+ self.class.shaders["font-sdf-#{font_name}"] ||= Raylib.LoadShaderFromMemory(nil, SDF_SHADER)
522
+ Raylib.BeginShaderMode(self.class.shaders["font-sdf-#{font_name}"])
523
+ end
524
+
398
525
  Raylib.DrawTextEx(fnt.raw, command.content.to_s, vec2(x, y), command.size, fnt.spacing, c)
399
- # content.free
526
+
527
+ if fnt.sdf
528
+ Raylib.EndShaderMode
529
+ end
400
530
  else
401
531
  Raylib.DrawText(command.content, x, y, command.size, c)
402
532
  end
@@ -453,8 +583,9 @@ module Hokusai::Backends
453
583
  end
454
584
  else
455
585
  rect = rect(command.background_boundary)
456
-
457
- if command.rounding > 0
586
+ if command.gradient
587
+ Raylib.DrawRectangleGradientEx(rect, color(command.gradient[0], true), color(command.gradient[1], true), color(command.gradient[2], true), color(command.gradient[3], true))
588
+ elsif command.rounding > 0
458
589
  Raylib.DrawRectangleRounded(rect, command.rounding, 50, background_color)
459
590
  else
460
591
  Raylib.DrawRectangleRec(rect, background_color)
@@ -3,8 +3,8 @@ module Hokusai::Backends
3
3
  class Config
4
4
  attr_accessor :width, :height, :fps, :init_flags,
5
5
  :title, :background, :automation_driver,
6
- :after_load_cb, :host, :port, :automated,
7
- :window_config_flags
6
+ :after_load_cb, :host, :port, :automated, :mobile,
7
+ :window_config_flags, :touch
8
8
 
9
9
  def after_load(&block)
10
10
  self.after_load_cb = block
@@ -14,16 +14,19 @@ module Hokusai::Backends
14
14
  @width = 500
15
15
  @height = 500
16
16
  @fps = 60
17
+ @touch = false
17
18
 
18
19
  @init_flags = ::SDL::INIT_VIDEO | ::SDL::INIT_EVENTS
19
- @window_config_flags = SDL::WINDOW_RESIZABLE
20
+ @window_config_flags = SDL::WINDOW_RESIZABLE | SDL::WINDOW_ALLOW_HIGHDPI
20
21
  @title = "(Unknown Title)"
21
22
  @background = SDLBackend.color(255,255,255, 0)
22
23
 
23
24
  after_load do
24
- font = Hokusai::Backends::SDLBackend::Font.from "#{__dir__}/Monaco.ttf"
25
- Hokusai.fonts.register "default", font
26
- Hokusai.fonts.activate "default"
25
+ if Hokusai.fonts.get("default").nil?
26
+ font = Hokusai::Backends::SDLBackend::Font.from "#{__dir__}/Monaco.ttf"
27
+ Hokusai.fonts.register "default", font
28
+ Hokusai.fonts.activate "default"
29
+ end
27
30
  end
28
31
  end
29
32
  end
@@ -21,7 +21,7 @@ module Hokusai::Backends
21
21
  end
22
22
 
23
23
  class Font < Hokusai::Font
24
- def self.from(file = "#{__dir__}/Monaco.ttf", size=50)
24
+ def self.from(file = "#{__dir__}/Monaco.ttf", size=60)
25
25
  raw = SDL.TTF_OpenFont(file, size)
26
26
 
27
27
  raise Hokusai::Error.new("Cannot open font from #{file}: #{ttf_error}") if raw.null?
@@ -51,6 +51,8 @@ module Hokusai::Backends
51
51
  set_style(**args)
52
52
 
53
53
  render_color = SDLBackend.color(color.r, color.g, color.b, color.a)
54
+ # bg = SDLBackend.color(0, 0, 0, 0)
55
+
54
56
  SDL.TTF_RenderUTF8_Blended(raw, text, render_color)
55
57
  end
56
58