rays 0.4.0 → 0.5.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/rays/bitmap.cpp +28 -8
  3. data/.doc/ext/rays/bounds.cpp +1 -1
  4. data/.doc/ext/rays/camera.cpp +5 -5
  5. data/.doc/ext/rays/color.cpp +1 -1
  6. data/.doc/ext/rays/color_space.cpp +10 -6
  7. data/.doc/ext/rays/font.cpp +116 -18
  8. data/.doc/ext/rays/image.cpp +27 -4
  9. data/.doc/ext/rays/matrix.cpp +1 -1
  10. data/.doc/ext/rays/painter.cpp +5 -5
  11. data/.doc/ext/rays/point.cpp +1 -1
  12. data/.doc/ext/rays/polygon.cpp +4 -4
  13. data/.doc/ext/rays/polyline.cpp +2 -2
  14. data/.doc/ext/rays/shader.cpp +2 -2
  15. data/.github/workflows/release-gem.yml +2 -49
  16. data/.github/workflows/tag.yml +5 -28
  17. data/.github/workflows/test.yml +1 -37
  18. data/ChangeLog.md +21 -0
  19. data/Gemfile.lock +13 -8
  20. data/Rakefile +2 -2
  21. data/VERSION +1 -1
  22. data/ext/rays/bitmap.cpp +28 -8
  23. data/ext/rays/bounds.cpp +1 -1
  24. data/ext/rays/camera.cpp +5 -5
  25. data/ext/rays/color.cpp +1 -1
  26. data/ext/rays/color_space.cpp +10 -6
  27. data/ext/rays/defs.h +3 -3
  28. data/ext/rays/extconf.rb +6 -5
  29. data/ext/rays/font.cpp +120 -18
  30. data/ext/rays/image.cpp +27 -4
  31. data/ext/rays/matrix.cpp +1 -1
  32. data/ext/rays/painter.cpp +5 -5
  33. data/ext/rays/point.cpp +1 -1
  34. data/ext/rays/polygon.cpp +4 -4
  35. data/ext/rays/polyline.cpp +2 -2
  36. data/ext/rays/shader.cpp +2 -2
  37. data/include/rays/bitmap.h +2 -0
  38. data/include/rays/font.h +46 -4
  39. data/include/rays/image.h +9 -5
  40. data/include/rays/painter.h +3 -1
  41. data/include/rays/ruby/color_space.h +2 -0
  42. data/include/rays/shader.h +3 -0
  43. data/lib/rays/font.rb +4 -1
  44. data/lib/rays/image.rb +2 -0
  45. data/lib/rays/painter.rb +5 -5
  46. data/rays.gemspec +3 -3
  47. data/src/bitmap.cpp +107 -0
  48. data/src/color.cpp +17 -0
  49. data/src/font.cpp +121 -25
  50. data/src/font.h +7 -5
  51. data/src/image.cpp +102 -100
  52. data/src/ios/font.mm +77 -24
  53. data/src/opengl/color_space.cpp +4 -1
  54. data/src/opengl/painter.cpp +86 -18
  55. data/src/opengl/shader.cpp +15 -13
  56. data/src/opengl/texture.cpp +2 -2
  57. data/src/opengl/win32/opengl.cpp +17 -12
  58. data/src/osx/font.mm +77 -24
  59. data/src/painter.cpp +12 -12
  60. data/src/painter.h +5 -1
  61. data/src/polygon.cpp +21 -21
  62. data/src/polyline.cpp +4 -4
  63. data/src/sdl/bitmap.cpp +16 -10
  64. data/src/sdl/font.cpp +56 -50
  65. data/src/win32/bitmap.cpp +22 -13
  66. data/src/win32/font.cpp +43 -44
  67. data/src/win32/gdi.cpp +43 -46
  68. data/src/win32/gdi.h +6 -1
  69. data/src/win32/rays.cpp +18 -1
  70. data/test/test_bitmap.rb +28 -10
  71. data/test/test_font.rb +58 -0
  72. data/test/test_image.rb +29 -6
  73. data/test/test_painter.rb +39 -0
  74. metadata +8 -8
  75. data/.github/workflows/utils.rb +0 -127
@@ -1,35 +1,12 @@
1
1
  name: Tag
2
2
 
3
3
  on:
4
- push:
4
+ workflow_run:
5
+ workflows: [Test]
6
+ types: [completed]
5
7
  branches: [master]
6
8
 
7
9
  jobs:
8
10
  tag:
9
- runs-on: ubuntu-latest
10
-
11
- steps:
12
- - name: ruby 3.2
13
- uses: ruby/setup-ruby@v1
14
- with:
15
- ruby-version: 3.2
16
-
17
- - name: checkout
18
- uses: actions/checkout@v4
19
- with:
20
- fetch-depth: 0
21
- token: ${{ secrets.PAT }}
22
-
23
- - name: setup dependencies
24
- run: "ruby -I.github/workflows -rutils -e 'setup_dependencies only: :xot'"
25
-
26
- - name: setup user name and email
27
- run: |
28
- git config --global user.email "xordog@gmail.com"
29
- git config --global user.name "xord"
30
-
31
- - name: tag versions
32
- run: "ruby -I.github/workflows -rutils -e 'tag_versions'"
33
-
34
- - name: push tags
35
- run: git push origin --tags
11
+ uses: xord/xot/.github/workflows/tag.yml@master
12
+ secrets: inherit
@@ -7,40 +7,4 @@ on:
7
7
 
8
8
  jobs:
9
9
  test:
10
- runs-on: macos-latest
11
-
12
- steps:
13
- - name: ruby 3.2
14
- uses: ruby/setup-ruby@v1
15
- with:
16
- ruby-version: 3.2
17
-
18
- - name: checkout
19
- uses: actions/checkout@v4
20
-
21
- - name: setup gems
22
- run: bundle install
23
-
24
- - name: setup dependencies
25
- run: "ruby -I.github/workflows -rutils -e 'setup_dependencies'"
26
-
27
- - name: packages
28
- run: bundle exec rake verbose packages
29
-
30
- - name: setup zig
31
- if: github.event.repository.name == 'reflex-terminal'
32
- uses: mlugg/setup-zig@v2
33
- with:
34
- version: 0.16.0
35
-
36
- - name: vendor
37
- run: bundle exec rake vendor
38
-
39
- - name: lib
40
- run: bundle exec rake verbose lib
41
-
42
- - name: ext
43
- run: bundle exec rake verbose ext
44
-
45
- - name: test
46
- run: bundle exec rake verbose test
10
+ uses: xord/xot/.github/workflows/test.yml@master
data/ChangeLog.md CHANGED
@@ -1,6 +1,27 @@
1
1
  # rays ChangeLog
2
2
 
3
3
 
4
+ ## [v0.5.0] - 2026-11-04
5
+
6
+ - [BREAKING] Store and blend alpha premultiplied on the GPU, so a fragment shader sees premultiplied samples and must emit premultiplied color
7
+ - [BREAKING] Bitmap#pixels exchanges straight alpha, not premultiplied
8
+ - [BREAKING] Size fonts in pixels on Windows, as on the other platforms
9
+ - [BREAKING] Font#name returns the name asked for, and Font#name(true) the name of the face the platform picked
10
+ - Add weight and italic to Font
11
+ - Add Font#italic? and #smooth?, and Image#smooth?
12
+ - Handle non-ASCII text and file paths on Windows
13
+ - Support High DPI on Windows
14
+ - Draw BGRA bitmaps on every platform
15
+ - Make a paint session that draws nothing cost almost nothing, and stop waiting for the GPU at its end
16
+
17
+ - Fix Font.new with no arguments sharing the default font, so that changing it changed every default font
18
+ - Fix text drawn off its baseline at a pixel density other than 1
19
+ - Fix a crash on the error paths, as loading a GIF from a missing file, on macOS
20
+ - Fix a crash in Font.families when the GC runs
21
+ - Fix an overflow of a font name longer than 31 characters on Windows
22
+ - Fix linking the extension statically on macOS
23
+
24
+
4
25
  ## [v0.4.0] - 2026-08-04
5
26
 
6
27
  - [BREAKING] Rename COLORSPACE_UNKNOWN to COLORSPACE_NONE
data/Gemfile.lock CHANGED
@@ -1,21 +1,26 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- power_assert (3.0.1)
5
- rake (13.3.1)
6
- test-unit (3.7.7)
4
+ power_assert (3.1.0)
5
+ rake (13.4.2)
6
+ test-unit (3.7.8)
7
7
  power_assert
8
- yard (0.9.39)
8
+ yard (0.9.45)
9
9
 
10
10
  PLATFORMS
11
- arm64-darwin-21
12
- arm64-darwin-23
13
- arm64-darwin-24
11
+ ruby
14
12
 
15
13
  DEPENDENCIES
16
14
  rake
17
15
  test-unit
18
16
  yard
19
17
 
18
+ CHECKSUMS
19
+ bundler (4.0.20) sha256=7978a8ac648767f5e635bc522445b79e80a52b907a39a36c2d8085ed6bc762ae
20
+ power_assert (3.1.0) sha256=fefe98ed5d3140628138f3f9f9194d6ece01f1320e69700d3c928adca7518251
21
+ rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
22
+ test-unit (3.7.8) sha256=689d1ca53f4d46f678b4e5d68d8e4294f87fc5e8b9238cc4de7c5727e8d65943
23
+ yard (0.9.45) sha256=52e211493f7cb8a3ebf7e104a25a1e73937a3103092545d34cb88fafebb3dc51
24
+
20
25
  BUNDLED WITH
21
- 2.4.19
26
+ 4.0.20
data/Rakefile CHANGED
@@ -37,7 +37,7 @@ use_external_library 'https://github.com/andrewwillmott/splines-lib',
37
37
  commit: '11e7240d57b0d22871aec3308186a5fcf915ba77',
38
38
  excludes: 'Test\.cpp',
39
39
  &proc {
40
- filter_file('Splines.cpp') do |cpp|
40
+ filter_file 'Splines.cpp' do |cpp|
41
41
  <<~EOS + cpp
42
42
  #include <cstdint>
43
43
  EOS
@@ -54,6 +54,6 @@ default_tasks :ext
54
54
  use_bundler
55
55
  build_native_library
56
56
  build_ruby_extension
57
- test_ruby_extension unless github_actions? && win32?
57
+ test_ruby_extension
58
58
  generate_documents
59
59
  build_ruby_gem
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.0
data/ext/rays/bitmap.cpp CHANGED
@@ -11,7 +11,7 @@ RUCY_DEFINE_VALUE_FROM_TO(RAYS_EXPORT, Rays::Bitmap)
11
11
 
12
12
  #define THIS to<Rays::Bitmap*>(self)
13
13
 
14
- #define CHECK RUCY_CHECK_OBJECT(Rays::Bitmap, self)
14
+ #define CHECK RUCY_CHECK_OBJ(Rays::Bitmap, self)
15
15
 
16
16
 
17
17
  static
@@ -24,7 +24,7 @@ RUCY_END
24
24
  static
25
25
  RUCY_DEFN(initialize)
26
26
  {
27
- RUCY_CHECK_OBJ(Rays::Bitmap, self);
27
+ RUCY_CHECK_PTR(Rays::Bitmap, self);
28
28
  check_arg_count(__FILE__, __LINE__, "Bitmap#initialize", argc, 2, 3);
29
29
 
30
30
  *THIS = Rays::Bitmap(
@@ -38,7 +38,7 @@ RUCY_END
38
38
  static
39
39
  RUCY_DEF1(initialize_copy, obj)
40
40
  {
41
- RUCY_CHECK_OBJ(Rays::Bitmap, self);
41
+ RUCY_CHECK_PTR(Rays::Bitmap, self);
42
42
 
43
43
  *THIS = to<Rays::Bitmap&>(obj).dup();
44
44
  return self;
@@ -73,7 +73,7 @@ RUCY_DEF0(color_space)
73
73
  RUCY_END
74
74
 
75
75
  static void
76
- set_pixels (Rays::Bitmap* bmp, Value pixels)
76
+ set_raw_pixels (Rays::Bitmap* bmp, Value pixels)
77
77
  {
78
78
  int w = bmp->width(), h = bmp->height();
79
79
  const auto& cs = bmp->color_space();
@@ -323,6 +323,23 @@ set_pixels (Rays::Bitmap* bmp, Value pixels)
323
323
  }
324
324
  }
325
325
 
326
+ static void
327
+ set_pixels (Rays::Bitmap* bmp, Value pixels)
328
+ {
329
+ const auto& cs = bmp->color_space();
330
+ if (!cs.has_alpha() || !cs.is_premult())
331
+ return set_raw_pixels(bmp, pixels);
332
+
333
+ int w = bmp->width(), h = bmp->height();
334
+ Rays::Bitmap straight(w, h, Rays::ColorSpace(cs.type(), false));
335
+ set_raw_pixels(&straight, pixels);
336
+
337
+ Rays::Bitmap premult = straight.dup(true);
338
+ size_t size = w * cs.Bpp();
339
+ for (int y = 0; y < h; ++y)
340
+ memcpy(bmp->at<uint8_t>(0, y), premult.at<uint8_t>(0, y), size);
341
+ }
342
+
326
343
  static inline uint32_t
327
344
  to_rgb (uint8_t r, uint8_t g, uint8_t b)
328
345
  {
@@ -608,7 +625,7 @@ get_32bit_pixels_string (const Rays::Bitmap& bmp)
608
625
  }
609
626
 
610
627
  return value(
611
- (const char*) &pixels[0], pixels.size() * sizeof(uint32_t),
628
+ (const char*) pixels.data(), pixels.size() * sizeof(uint32_t),
612
629
  rb_ascii8bit_encoding());
613
630
  }
614
631
 
@@ -627,14 +644,17 @@ RUCY_DEF0(get_pixels)
627
644
  {
628
645
  CHECK;
629
646
 
647
+ const auto& cs = THIS->color_space();
648
+ Rays::Bitmap bmp = cs.has_alpha() && cs.is_premult() ? THIS->dup(false) : *THIS;
649
+
630
650
  #ifdef RAYS_32BIT_PIXELS_STRING
631
- Value str = get_32bit_pixels_string(*THIS);
651
+ Value str = get_32bit_pixels_string(bmp);
632
652
  if (str) return str;
633
653
  #endif
634
654
 
635
655
  std::vector<VALUE> pixels;
636
- get_pixels(&pixels, *THIS);
637
- return array((const Value*) &pixels[0], pixels.size());
656
+ get_pixels(&pixels, bmp);
657
+ return array((const Value*) pixels.data(), pixels.size());
638
658
  }
639
659
  RUCY_END
640
660
 
data/ext/rays/bounds.cpp CHANGED
@@ -9,7 +9,7 @@ RUCY_DEFINE_VALUE_OR_ARRAY_FROM_TO(RAYS_EXPORT, Rays::Bounds)
9
9
 
10
10
  #define THIS to<Rays::Bounds*>(self)
11
11
 
12
- #define CHECK RUCY_CHECK_OBJ(Rays::Bounds, self)
12
+ #define CHECK RUCY_CHECK_PTR(Rays::Bounds, self)
13
13
 
14
14
 
15
15
  static
data/ext/rays/camera.cpp CHANGED
@@ -10,7 +10,7 @@ RUCY_DEFINE_VALUE_FROM_TO(RAYS_EXPORT, Rays::Camera)
10
10
 
11
11
  #define THIS to<Rays::Camera*>(self)
12
12
 
13
- #define CHECK RUCY_CHECK_OBJECT(Rays::Camera, self)
13
+ #define CHECK RUCY_CHECK_OBJ(Rays::Camera, self)
14
14
 
15
15
 
16
16
  static
@@ -23,7 +23,7 @@ RUCY_END
23
23
  static
24
24
  RUCY_DEF5(initialize, device_name, min_width, min_height, resize, crop)
25
25
  {
26
- RUCY_CHECK_OBJ(Rays::Camera, self);
26
+ RUCY_CHECK_PTR(Rays::Camera, self);
27
27
 
28
28
  *THIS = Rays::Camera(
29
29
  device_name ? device_name.c_str() : NULL,
@@ -146,10 +146,10 @@ RUCY_DEF0(device_names)
146
146
  {
147
147
  auto names = Rays::get_camera_device_names();
148
148
 
149
- std::vector<Value> v;
149
+ Value v = array(NULL, names.size());
150
150
  for (const auto& name : names)
151
- v.emplace_back(name.c_str());
152
- return array(&v[0], v.size());
151
+ v.push(name.c_str());
152
+ return v;
153
153
  }
154
154
  RUCY_END
155
155
 
data/ext/rays/color.cpp CHANGED
@@ -10,7 +10,7 @@ RUCY_DEFINE_VALUE_OR_ARRAY_FROM_TO(RAYS_EXPORT, Rays::Color)
10
10
 
11
11
  #define THIS to<Rays::Color*>(self)
12
12
 
13
- #define CHECK RUCY_CHECK_OBJ(Rays::Color, self)
13
+ #define CHECK RUCY_CHECK_PTR(Rays::Color, self)
14
14
 
15
15
 
16
16
  static const char* NIL_COLOR_NO = "no";
@@ -6,9 +6,11 @@
6
6
 
7
7
  RUCY_DEFINE_VALUE_OR_ARRAY_FROM_TO(RAYS_EXPORT, Rays::ColorSpace)
8
8
 
9
+ RUCY_DEFINE_CONVERT_TO(RAYS_EXPORT, Rays::ColorSpaceType)
10
+
9
11
  #define THIS to<Rays::ColorSpace*>(self)
10
12
 
11
- #define CHECK RUCY_CHECK_OBJECT(Rays::ColorSpace, self)
13
+ #define CHECK RUCY_CHECK_OBJ(Rays::ColorSpace, self)
12
14
 
13
15
 
14
16
  static struct ColorSpaceEnum
@@ -72,7 +74,7 @@ RUCY_END
72
74
  static
73
75
  RUCY_DEFN(initialize)
74
76
  {
75
- RUCY_CHECK_OBJ(Rays::ColorSpace, self);
77
+ RUCY_CHECK_PTR(Rays::ColorSpace, self);
76
78
  check_arg_count(__FILE__, __LINE__, "ColorSpace#initialize", argc, 1, 2);
77
79
 
78
80
  *THIS = to<Rays::ColorSpace>(argc, argv);
@@ -248,13 +250,15 @@ namespace Rucy
248
250
 
249
251
 
250
252
  template <> RAYS_EXPORT Rays::ColorSpaceType
251
- value_to<Rays::ColorSpaceType> (Value value, bool convert)
253
+ value_to<Rays::ColorSpaceType> (int argc, const Value* argv, bool convert)
252
254
  {
255
+ assert(argc > 0 && argv);
256
+
253
257
  if (convert)
254
258
  {
255
- if (value.is_s() || value.is_sym())
259
+ if (argv->is_s() || argv->is_sym())
256
260
  {
257
- const char* str = value.c_str();
261
+ const char* str = argv->c_str();
258
262
  for (size_t i = 0; i < COLOR_SPACES_SIZE; ++i)
259
263
  {
260
264
  if (strcasecmp(str, COLOR_SPACES[i].name) == 0)
@@ -263,7 +267,7 @@ namespace Rucy
263
267
  }
264
268
  }
265
269
 
266
- uint type = value_to<uint>(value, convert);
270
+ uint type = value_to<uint>(*argv, convert);
267
271
  if (type >= Rays::COLORSPACE_MAX)
268
272
  argument_error(__FILE__, __LINE__, "invalid color space type -- %d", type);
269
273
 
data/ext/rays/defs.h CHANGED
@@ -72,17 +72,17 @@ struct CreateParams
72
72
 
73
73
  const Rays::Point* ppoints () const
74
74
  {
75
- return points.empty() ? NULL : &points[0];
75
+ return points.empty() ? NULL : points.data();
76
76
  }
77
77
 
78
78
  const Rays::Color* pcolors () const
79
79
  {
80
- return colors.empty() ? NULL : &colors[0];
80
+ return colors.empty() ? NULL : colors.data();
81
81
  }
82
82
 
83
83
  const Rays::Point* ptexcoords () const
84
84
  {
85
- return texcoords.empty() ? NULL : &texcoords[0];
85
+ return texcoords.empty() ? NULL : texcoords.data();
86
86
  }
87
87
 
88
88
  size_t size () const
data/ext/rays/extconf.rb CHANGED
@@ -12,11 +12,12 @@ require 'rays/extension'
12
12
  Xot::ExtConf.new Xot, Rucy, Rays do
13
13
  setup do
14
14
  headers << 'ruby.h'
15
- libs.unshift 'gdi32', 'opengl32', 'glew32' if win32?
16
- libs.unshift 'SDL2', 'SDL2_ttf', 'GLEW', 'GL' if linux? || wasm?
17
- frameworks << 'AppKit' << 'OpenGL' << 'AVFoundation' if osx?
18
- $CPPFLAGS << ' -DRAYS_32BIT_PIXELS_STRING' if RUBY_PLATFORM == 'x64-mingw-ucrt'
19
- $LDFLAGS << ' -Wl,--out-implib=librays.dll.a' if mingw? || cygwin?
15
+ libs.unshift 'gdi32', 'opengl32', 'glew32' if win32?
16
+ libs.unshift 'SDL2', 'SDL2_ttf', 'GLEW', 'GL' if linux? || wasm?
17
+ frameworks.concat %w[AppKit OpenGL
18
+ AVFoundation CoreMedia CoreImage CoreVideo] if osx?
19
+ $CPPFLAGS << ' -DRAYS_32BIT_PIXELS_STRING' if RUBY_PLATFORM == 'x64-mingw-ucrt'
20
+ $LDFLAGS << ' -Wl,--out-implib=librays.dll.a' if mingw? || cygwin?
20
21
  end
21
22
 
22
23
  create_makefile 'rays_ext'
data/ext/rays/font.cpp CHANGED
@@ -1,6 +1,7 @@
1
1
  #include "rays/ruby/font.h"
2
2
 
3
3
 
4
+ #include <strings.h>
4
5
  #include "defs.h"
5
6
 
6
7
 
@@ -8,7 +9,7 @@ RUCY_DEFINE_VALUE_OR_ARRAY_FROM_TO(RAYS_EXPORT, Rays::Font)
8
9
 
9
10
  #define THIS to<Rays::Font*>(self)
10
11
 
11
- #define CHECK RUCY_CHECK_OBJECT(Rays::Font, self)
12
+ #define CHECK RUCY_CHECK_OBJ(Rays::Font, self)
12
13
 
13
14
 
14
15
  static
@@ -21,7 +22,7 @@ RUCY_END
21
22
  static
22
23
  RUCY_DEFN(initialize)
23
24
  {
24
- RUCY_CHECK_OBJ(Rays::Font, self);
25
+ RUCY_CHECK_PTR(Rays::Font, self);
25
26
  check_arg_count(__FILE__, __LINE__, "Font#initialize", argc, 0, 1, 2, 3);
26
27
 
27
28
  *THIS = to<Rays::Font>(argc, argv);
@@ -32,7 +33,7 @@ RUCY_END
32
33
  static
33
34
  RUCY_DEF1(initialize_copy, obj)
34
35
  {
35
- RUCY_CHECK_OBJ(Rays::Font, self);
36
+ RUCY_CHECK_PTR(Rays::Font, self);
36
37
 
37
38
  *THIS = to<Rays::Font&>(obj).dup();
38
39
  return self;
@@ -40,10 +41,13 @@ RUCY_DEF1(initialize_copy, obj)
40
41
  RUCY_END
41
42
 
42
43
  static
43
- RUCY_DEF0(name)
44
+ RUCY_DEFN(name)
44
45
  {
45
46
  CHECK;
46
- return value(THIS->name().c_str());
47
+ check_arg_count(__FILE__, __LINE__, "Font#name", argc, 0, 1);
48
+
49
+ bool resolved = argc >= 1 ? to<bool>(argv[0]) : false;
50
+ return value(THIS->name(resolved).c_str());
47
51
  }
48
52
  RUCY_END
49
53
 
@@ -64,6 +68,74 @@ RUCY_DEF0(size)
64
68
  }
65
69
  RUCY_END
66
70
 
71
+ static int
72
+ to_font_weight (Value weight)
73
+ {
74
+ if (weight.is_s() || weight.is_sym())
75
+ {
76
+ static const struct {const char* name; int weight;} WEIGHTS[] =
77
+ {
78
+ // most used first
79
+ {"normal", Rays::Font::WEIGHT_NORMAL},
80
+ {"regular", Rays::Font::WEIGHT_NORMAL},
81
+ {"bold", Rays::Font::WEIGHT_BOLD},
82
+
83
+ {"thin", Rays::Font::WEIGHT_THIN},
84
+ {"extralight", Rays::Font::WEIGHT_EXTRALIGHT},
85
+ {"light", Rays::Font::WEIGHT_LIGHT},
86
+ {"medium", Rays::Font::WEIGHT_MEDIUM},
87
+ {"semibold", Rays::Font::WEIGHT_SEMIBOLD},
88
+ {"extrabold", Rays::Font::WEIGHT_EXTRABOLD},
89
+ {"black", Rays::Font::WEIGHT_BLACK},
90
+ };
91
+
92
+ const char* name = weight.c_str();
93
+ for (const auto& w : WEIGHTS)
94
+ {
95
+ if (strcasecmp(name, w.name) == 0)
96
+ return w.weight;
97
+ }
98
+
99
+ argument_error(
100
+ __FILE__, __LINE__, "unknown font weight: %s", weight.inspect().c_str());
101
+ }
102
+ return to<int>(weight);
103
+ }
104
+
105
+ static
106
+ RUCY_DEF1(set_weight, weight)
107
+ {
108
+ CHECK;
109
+ THIS->set_weight(to_font_weight(weight));
110
+ return weight;
111
+ }
112
+ RUCY_END
113
+
114
+ static
115
+ RUCY_DEF0(weight)
116
+ {
117
+ CHECK;
118
+ return value(THIS->weight());
119
+ }
120
+ RUCY_END
121
+
122
+ static
123
+ RUCY_DEF1(set_italic, italic)
124
+ {
125
+ CHECK;
126
+ THIS->set_italic(to<bool>(italic));
127
+ return italic;
128
+ }
129
+ RUCY_END
130
+
131
+ static
132
+ RUCY_DEF0(get_italic)
133
+ {
134
+ CHECK;
135
+ return value(THIS->italic());
136
+ }
137
+ RUCY_END
138
+
67
139
  static
68
140
  RUCY_DEF1(set_smooth, smooth)
69
141
  {
@@ -74,7 +146,7 @@ RUCY_DEF1(set_smooth, smooth)
74
146
  RUCY_END
75
147
 
76
148
  static
77
- RUCY_DEF0(smooth)
149
+ RUCY_DEF0(get_smooth)
78
150
  {
79
151
  CHECK;
80
152
  return value(THIS->smooth());
@@ -133,10 +205,10 @@ RUCY_DEF0(families)
133
205
  Hash hash;
134
206
  for (const auto& family : Rays::get_font_families())
135
207
  {
136
- std::vector<Value> members;
208
+ Value members = array(NULL, family.second.size());
137
209
  for (const auto& member : family.second)
138
- members.emplace_back(member.c_str());
139
- hash.set(family.first.c_str(), array(&members[0], members.size()));
210
+ members.push(member.c_str());
211
+ hash.set(family.first.c_str(), members);
140
212
  }
141
213
  return hash;
142
214
  }
@@ -171,8 +243,12 @@ Init_rays_font ()
171
243
  cFont.define_method("name", name);
172
244
  cFont.define_method("size=", set_size);
173
245
  cFont.define_method("size", size);
246
+ cFont.define_method("weight=", set_weight);
247
+ cFont.define_method("weight", weight);
248
+ cFont.define_method("italic=", set_italic);
249
+ cFont.define_method("italic", get_italic);
174
250
  cFont.define_method("smooth=", set_smooth);
175
- cFont.define_method("smooth", smooth);
251
+ cFont.define_method("smooth", get_smooth);
176
252
  cFont.define_method("width", width);
177
253
  cFont.define_method("height", height);
178
254
  cFont.define_method("ascent", ascent);
@@ -180,6 +256,18 @@ Init_rays_font ()
180
256
  cFont.define_method("leading", leading);
181
257
  cFont.define_module_function("families", families);
182
258
  cFont.define_module_function("load", load);
259
+
260
+ cFont.define_const("WEIGHT_MIN", Rays::Font::WEIGHT_MIN);
261
+ cFont.define_const("WEIGHT_THIN", Rays::Font::WEIGHT_THIN);
262
+ cFont.define_const("WEIGHT_EXTRALIGHT", Rays::Font::WEIGHT_EXTRALIGHT);
263
+ cFont.define_const("WEIGHT_LIGHT", Rays::Font::WEIGHT_LIGHT);
264
+ cFont.define_const("WEIGHT_NORMAL", Rays::Font::WEIGHT_NORMAL);
265
+ cFont.define_const("WEIGHT_MEDIUM", Rays::Font::WEIGHT_MEDIUM);
266
+ cFont.define_const("WEIGHT_SEMIBOLD", Rays::Font::WEIGHT_SEMIBOLD);
267
+ cFont.define_const("WEIGHT_BOLD", Rays::Font::WEIGHT_BOLD);
268
+ cFont.define_const("WEIGHT_EXTRABOLD", Rays::Font::WEIGHT_EXTRABOLD);
269
+ cFont.define_const("WEIGHT_BLACK", Rays::Font::WEIGHT_BLACK);
270
+ cFont.define_const("WEIGHT_MAX", Rays::Font::WEIGHT_MAX);
183
271
  }
184
272
 
185
273
 
@@ -198,16 +286,30 @@ namespace Rucy
198
286
 
199
287
  if (convert)
200
288
  {
201
- if (argc == 0)
289
+ Value options = argc >= 1 && argv[argc - 1].is_hash() ? argv[--argc] : nil();
290
+ if (argc == 0 && !options)
202
291
  return Rays::get_default_font();
203
292
 
204
- coord size = argc >= 2 ? to<coord>(argv[1]) : (coord) Rays::Font::DEFAULT_SIZE;
205
- bool smooth = argc >= 3 ? to<bool>(argv[2]) : true;
206
-
207
- if (argv->is_nil())
208
- return Rays::Font(NULL, size, smooth);
209
- else if (argv->is_s() || argv->is_sym())
210
- return Rays::Font(argv[0].c_str(), size, smooth);
293
+ int weight = Rays::Font::DEFAULT_WEIGHT;
294
+ bool italic = false;
295
+ bool smooth = true;
296
+ if (options)
297
+ {
298
+ RUCY_SYMBOL(weight_sym, "weight");
299
+ RUCY_SYMBOL(italic_sym, "italic");
300
+ RUCY_SYMBOL(smooth_sym, "smooth");
301
+ Value v;
302
+ if (!(v = options.get(weight_sym.value())).is_nil()) weight = to_font_weight(v);
303
+ if (!(v = options.get(italic_sym.value())).is_nil()) italic = to<bool>(v);
304
+ if (!(v = options.get(smooth_sym.value())).is_nil()) smooth = to<bool>(v);
305
+ }
306
+
307
+ if (argc == 0 || argv->is_nil() || argv->is_s() || argv->is_sym())
308
+ {
309
+ const char* name = argc >= 1 && !argv[0].is_nil() ? argv[0].c_str() : NULL;
310
+ coord size = argc >= 2 ? to<coord>(argv[1]) : (coord) Rays::Font::DEFAULT_SIZE;
311
+ return Rays::Font(name, size, weight, italic, smooth);
312
+ }
211
313
  }
212
314
 
213
315
  if (argc != 1)
data/ext/rays/image.cpp CHANGED
@@ -7,11 +7,31 @@
7
7
  #include "defs.h"
8
8
 
9
9
 
10
- RUCY_DEFINE_VALUE_FROM_TO(RAYS_EXPORT, Rays::Image)
10
+ RUCY_DEFINE_VALUE_TO(RAYS_EXPORT, Rays::Image)
11
+
12
+ namespace Rucy
13
+ {
14
+
15
+ // An image with a loader is read-only, so its ruby object is frozen
16
+ RAYS_EXPORT Value
17
+ value (const Rays::Image& obj)
18
+ {
19
+ Value v = new_type(get_ruby_class<Rays::Image>(), new Rays::Image(obj));
20
+ if (obj.loader()) v.freeze();
21
+ return v;
22
+ }
23
+
24
+ RAYS_EXPORT Value
25
+ value (const Rays::Image* obj)
26
+ {
27
+ return obj ? value(*obj) : nil();
28
+ }
29
+
30
+ }// Rucy
11
31
 
12
32
  #define THIS to<Rays::Image*>(self)
13
33
 
14
- #define CHECK RUCY_CHECK_OBJECT(Rays::Image, self)
34
+ #define CHECK RUCY_CHECK_OBJ(Rays::Image, self)
15
35
 
16
36
 
17
37
  static
@@ -24,7 +44,7 @@ RUCY_END
24
44
  static
25
45
  RUCY_DEF3(initialize, args, pixel_density, smooth)
26
46
  {
27
- RUCY_CHECK_OBJ(Rays::Image, self);
47
+ RUCY_CHECK_PTR(Rays::Image, self);
28
48
 
29
49
  size_t argc = args.size();
30
50
  check_arg_count(__FILE__, __LINE__, "Image#initialize!", argc, 1, 2, 3);
@@ -53,7 +73,7 @@ RUCY_END
53
73
  static
54
74
  RUCY_DEF1(initialize_copy, obj)
55
75
  {
56
- RUCY_CHECK_OBJ(Rays::Image, self);
76
+ RUCY_CHECK_PTR(Rays::Image, self);
57
77
 
58
78
  *THIS = to<Rays::Image&>(obj).dup();
59
79
  return self;
@@ -105,6 +125,7 @@ static
105
125
  RUCY_DEF0(painter)
106
126
  {
107
127
  CHECK;
128
+ self.check_frozen();
108
129
  return value(THIS->painter());
109
130
  }
110
131
  RUCY_END
@@ -113,6 +134,7 @@ static
113
134
  RUCY_DEF1(get_bitmap, modify)
114
135
  {
115
136
  CHECK;
137
+ if (modify) self.check_frozen();
116
138
  return value(THIS->bitmap(modify));
117
139
  }
118
140
  RUCY_END
@@ -121,6 +143,7 @@ static
121
143
  RUCY_DEF1(set_smooth, smooth)
122
144
  {
123
145
  CHECK;
146
+ self.check_frozen();
124
147
  THIS->set_smooth(smooth);
125
148
  return smooth;
126
149
  }