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
data/src/osx/font.mm CHANGED
@@ -6,6 +6,7 @@
6
6
  #import <ApplicationServices/ApplicationServices.h>
7
7
  #import <AppKit/AppKit.h>
8
8
  #include <xot/string.h>
9
+ #include <xot/util.h>
9
10
  #include "rays/exception.h"
10
11
 
11
12
 
@@ -17,6 +18,8 @@ namespace Rays
17
18
 
18
19
  typedef std::shared_ptr<const __CFAttributedString> CFAttributedStringPtr;
19
20
 
21
+ typedef std::shared_ptr<const __CTFontDescriptor> CTFontDescriptorPtr;
22
+
20
23
  typedef std::shared_ptr<CGDataProvider> CGDataProviderPtr;
21
24
 
22
25
  typedef std::shared_ptr<CGFont> CGFontPtr;
@@ -29,8 +32,6 @@ namespace Rays
29
32
 
30
33
  CTFontRef font = NULL;
31
34
 
32
- String path;
33
-
34
35
  ~Data ()
35
36
  {
36
37
  if (font)
@@ -43,6 +44,63 @@ namespace Rays
43
44
  };// RawFont::Data
44
45
 
45
46
 
47
+ static const struct {int weight; CGFloat native;} NATIVE_WEIGHTS[] =
48
+ {
49
+ {Font::WEIGHT_MIN, -1.0},
50
+ {Font::WEIGHT_THIN, NSFontWeightUltraLight},
51
+ {Font::WEIGHT_EXTRALIGHT, NSFontWeightThin},
52
+ {Font::WEIGHT_LIGHT, NSFontWeightLight},
53
+ {Font::WEIGHT_NORMAL, NSFontWeightRegular},
54
+ {Font::WEIGHT_MEDIUM, NSFontWeightMedium},
55
+ {Font::WEIGHT_SEMIBOLD, NSFontWeightSemibold},
56
+ {Font::WEIGHT_BOLD, NSFontWeightBold},
57
+ {Font::WEIGHT_EXTRABOLD, NSFontWeightHeavy},
58
+ {Font::WEIGHT_BLACK, NSFontWeightBlack},
59
+ {Font::WEIGHT_MAX, 1.0}
60
+ };
61
+
62
+ static CGFloat
63
+ to_native_weight (int weight)
64
+ {
65
+ size_t last = sizeof(NATIVE_WEIGHTS) / sizeof(NATIVE_WEIGHTS[0]) - 1;
66
+ for (size_t i = 1; i <= last; ++i)
67
+ {
68
+ if (weight > NATIVE_WEIGHTS[i].weight) continue;
69
+
70
+ const auto& lo = NATIVE_WEIGHTS[i - 1];
71
+ const auto& hi = NATIVE_WEIGHTS[i];
72
+ CGFloat t = (CGFloat) (weight - lo.weight) / (hi.weight - lo.weight);
73
+ return lo.native + (hi.native - lo.native) * t;
74
+ }
75
+ return NATIVE_WEIGHTS[last].native;
76
+ }
77
+
78
+ static CTFontRef
79
+ create_styled_font (CTFontRef base, coord size, int weight, bool italic)
80
+ {
81
+ Xot::CFStringPtr family(CTFontCopyFamilyName(base), Xot::safe_cfrelease);
82
+ if (!family) return NULL;
83
+
84
+ NSDictionary* traits =
85
+ @{
86
+ (id) kCTFontWeightTrait: @(to_native_weight(weight)),
87
+ (id) kCTFontSymbolicTrait: @(italic ? kCTFontTraitItalic : 0)
88
+ };
89
+ NSDictionary* attributes =
90
+ @{
91
+ (id) kCTFontFamilyNameAttribute: (__bridge NSString*) family.get(),
92
+ (id) kCTFontTraitsAttribute: traits
93
+ };
94
+
95
+ CTFontDescriptorPtr descriptor(
96
+ CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef) attributes),
97
+ Xot::safe_cfrelease);
98
+ if (!descriptor) return NULL;
99
+
100
+ return CTFontCreateWithFontDescriptor(descriptor.get(), size, NULL);
101
+ }
102
+
103
+
46
104
  static CTLinePtr
47
105
  make_line (CTFontRef font, const char* str)
48
106
  {
@@ -63,15 +121,15 @@ namespace Rays
63
121
  CFDictionaryCreate(
64
122
  NULL, (const void**) &keys, (const void**) &values, nkeys,
65
123
  &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks),
66
- CFRelease);
124
+ Xot::safe_cfrelease);
67
125
 
68
126
  CFAttributedStringPtr attrstr(
69
127
  CFAttributedStringCreate(NULL, Xot::String(str).to_cfstr().get(), attr.get()),
70
- CFRelease);
128
+ Xot::safe_cfrelease);
71
129
 
72
130
  return CTLinePtr(
73
131
  CTLineCreateWithAttributedString(attrstr.get()),
74
- CFRelease);
132
+ Xot::safe_cfrelease);
75
133
  }
76
134
 
77
135
  const FontFamilyMap&
@@ -118,7 +176,6 @@ namespace Rays
118
176
 
119
177
  RawFont rawfont;
120
178
  rawfont.self->font = ctfont;
121
- rawfont.self->path = path;
122
179
  return rawfont;
123
180
  }
124
181
 
@@ -127,20 +184,23 @@ namespace Rays
127
184
  {
128
185
  }
129
186
 
130
- RawFont::RawFont (const char* name, coord size)
187
+ RawFont::RawFont (const char* name, coord size, int weight, bool italic)
131
188
  {
132
- self->font = name
189
+ CTFontRef font = name
133
190
  ? CTFontCreateWithName(Xot::String(name).to_cfstr().get(), size, NULL)
134
191
  : CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, size, NULL);
135
- }
136
192
 
137
- RawFont::RawFont (const This& obj, coord size)
138
- {
139
- const char* path = obj.self->path.empty() ? NULL : obj.self->path.c_str();
140
- if (path)
141
- *this = RawFont_load(path, size);
142
- else
143
- self->font = CTFontCreateWithName(obj.name().to_cfstr().get(), size, NULL);
193
+ if (font && (weight != Font::WEIGHT_NORMAL || italic))
194
+ {
195
+ CTFontRef styled = create_styled_font(font, size, weight, italic);
196
+ if (styled)
197
+ {
198
+ CFRelease(font);
199
+ font = styled;
200
+ }
201
+ }
202
+
203
+ self->font = font;
144
204
  }
145
205
 
146
206
  RawFont::~RawFont ()
@@ -189,17 +249,10 @@ namespace Rays
189
249
  {
190
250
  if (!*this) return "";
191
251
 
192
- Xot::CFStringPtr str(CTFontCopyFullName(self->font), CFRelease);
252
+ Xot::CFStringPtr str(CTFontCopyFullName(self->font), Xot::safe_cfrelease);
193
253
  return Xot::to_s(str);
194
254
  }
195
255
 
196
- coord
197
- RawFont::size () const
198
- {
199
- if (!*this) return 0;
200
- return CTFontGetSize(self->font);
201
- }
202
-
203
256
  coord
204
257
  RawFont::get_width (const char* str) const
205
258
  {
data/src/painter.cpp CHANGED
@@ -7,6 +7,7 @@
7
7
  #include "rays/debug.h"
8
8
  #include "polygon.h"
9
9
  #include "image.h"
10
+ #include "font.h"
10
11
 
11
12
 
12
13
  namespace Rays
@@ -741,21 +742,20 @@ namespace Rays
741
742
  return self->state.clip;
742
743
  }
743
744
 
744
- static bool
745
- has_same_font (const Font& font, const char* name, coord size, bool smooth)
746
- {
747
- return
748
- font.size() == size &&
749
- font.smooth() == smooth &&
750
- font.name() == (name ? name : get_default_font().name().c_str());
751
- }
752
-
753
745
  void
754
- Painter::set_font (const char* name, coord size, bool smooth)
746
+ Painter::set_font (
747
+ const char* name, coord size, int weight, bool italic, bool smooth)
755
748
  {
756
- if (has_same_font(self->state.font, name, size, smooth)) return;
749
+ if (weight < 0)
750
+ weight = Font::DEFAULT_WEIGHT;
751
+
752
+ if (Font_has_same_attributes(
753
+ self->state.font, name, size, weight, italic, smooth))
754
+ {
755
+ return;
756
+ }
757
757
 
758
- set_font(Font(name, size, smooth));
758
+ set_font(Font(name, size, weight, italic, smooth));
759
759
  }
760
760
 
761
761
  void
data/src/painter.h CHANGED
@@ -179,7 +179,9 @@ namespace Rays
179
179
 
180
180
  PAINTING = Xot::bit(1, Painter::FLAG_LAST),
181
181
 
182
- UNBATCHABLE_STATE_CHANGED = Xot::bit(2, Painter::FLAG_LAST),
182
+ CLEAR_DEPTH = Xot::bit(2, Painter::FLAG_LAST),
183
+
184
+ UNBATCHABLE_STATE_CHANGED = Xot::bit(3, Painter::FLAG_LAST),
183
185
 
184
186
  };// Flag
185
187
 
@@ -237,6 +239,8 @@ namespace Rays
237
239
  Painter* painter, const Font& font, const char* line, coord x, coord y,
238
240
  coord width = 0, coord height = 0);
239
241
 
242
+ bool Painter_get_pixel (Color* color, Painter* painter, coord x, coord y);
243
+
240
244
 
241
245
  }// Rays
242
246
 
data/src/polygon.cpp CHANGED
@@ -147,18 +147,18 @@ namespace Rays
147
147
  {
148
148
  draw_polygon(
149
149
  painter, MODE_TRIANGLES,
150
- &points[0], points.size(),
151
- &indices[0], indices.size(),
152
- &(*pcolors)[0],
153
- ptexcoords ? &(*ptexcoords)[0] : NULL);
150
+ points.data(), points.size(),
151
+ indices.data(), indices.size(),
152
+ pcolors->data(),
153
+ ptexcoords ? ptexcoords->data() : NULL);
154
154
  }
155
155
  else
156
156
  {
157
157
  draw_polygon(
158
158
  painter, MODE_TRIANGLES, color,
159
- &points[0], points.size(),
160
- &indices[0], indices.size(),
161
- ptexcoords ? &(*ptexcoords)[0] : NULL);
159
+ points.data(), points.size(),
160
+ indices.data(), indices.size(),
161
+ ptexcoords ? ptexcoords->data() : NULL);
162
162
  }
163
163
  }
164
164
 
@@ -227,7 +227,7 @@ namespace Rays
227
227
  size_t index_offset = 0;
228
228
  for (const auto& seg : segments)
229
229
  {
230
- Polyline polyline(&points[0] + seg.begin, seg.end - seg.begin);
230
+ Polyline polyline(points.data() + seg.begin, seg.end - seg.begin);
231
231
  if (!seg.hole)
232
232
  {
233
233
  triangulate(polylines, index_offset);
@@ -902,7 +902,7 @@ namespace Rays
902
902
  points.emplace_back(make_ellipse_point(
903
903
  x, y, width, height, radian_from, radian_to, nsegment, seg));
904
904
  }
905
- append(Polyline(&points[0], points.size(), true));
905
+ append(Polyline(points.data(), points.size(), true));
906
906
 
907
907
  if (has_hole)
908
908
  {
@@ -916,7 +916,7 @@ namespace Rays
916
916
  hole_x, hole_y, hole_size.x, hole_size.y,
917
917
  radian_from, radian_to, nsegment, seg));
918
918
  }
919
- append(Polyline(&points[0], points.size(), true, NULL, NULL, true));
919
+ append(Polyline(points.data(), points.size(), true, NULL, NULL, true));
920
920
  }
921
921
  }
922
922
 
@@ -961,7 +961,7 @@ namespace Rays
961
961
  }
962
962
  }
963
963
 
964
- append(Polyline(&points[0], points.size(), true));
964
+ append(Polyline(points.data(), points.size(), true));
965
965
  }
966
966
 
967
967
  Point make_ellipse_point (
@@ -1040,7 +1040,7 @@ namespace Rays
1040
1040
  array.reserve(size + 1);
1041
1041
  array.insert(array.begin(), points, points + size);
1042
1042
  array.emplace_back(points[0]);
1043
- polygon->self->append(Polyline(&array[0], array.size(), true, false));
1043
+ polygon->self->append(Polyline(array.data(), array.size(), true, false));
1044
1044
  }
1045
1045
  #endif
1046
1046
  return p;
@@ -1138,9 +1138,9 @@ namespace Rays
1138
1138
  }
1139
1139
 
1140
1140
  p.self->append(Polyline(
1141
- &points_[0], points_.size(), true,
1142
- pcolors_ ? &(*pcolors_)[0] : NULL,
1143
- ptexcoords_ ? &(*ptexcoords_)[0] : NULL));
1141
+ points_.data(), points_.size(), true,
1142
+ pcolors_ ? pcolors_->data() : NULL,
1143
+ ptexcoords_ ? ptexcoords_->data() : NULL));
1144
1144
  if (size >= 4)
1145
1145
  {
1146
1146
  p.self->append(Polyline(
@@ -1297,9 +1297,9 @@ namespace Rays
1297
1297
  }
1298
1298
 
1299
1299
  p.self->append(Polyline(
1300
- &points_[0], points_.size(), true,
1301
- pcolors_ ? &(*pcolors_)[0] : NULL,
1302
- ptexcoords_ ? &(*ptexcoords_)[0] : NULL));
1300
+ points_.data(), points_.size(), true,
1301
+ pcolors_ ? pcolors_->data() : NULL,
1302
+ ptexcoords_ ? ptexcoords_->data() : NULL));
1303
1303
  for (size_t i = 2; i < in_last; i += 2)
1304
1304
  {
1305
1305
  p.self->append(Polyline(
@@ -1410,7 +1410,7 @@ namespace Rays
1410
1410
  }
1411
1411
  }
1412
1412
 
1413
- return create_line(&result[0], result.size(), loop);
1413
+ return create_line(result.data(), result.size(), loop);
1414
1414
  }
1415
1415
 
1416
1416
  Polygon
@@ -1632,7 +1632,7 @@ namespace Rays
1632
1632
  for (const auto& polyline : lhs)
1633
1633
  polylines.emplace_back(polyline);
1634
1634
  polylines.emplace_back(rhs);
1635
- return Polygon(&polylines[0], polylines.size());
1635
+ return Polygon(polylines.data(), polylines.size());
1636
1636
  }
1637
1637
 
1638
1638
  Polygon
@@ -1641,7 +1641,7 @@ namespace Rays
1641
1641
  std::vector<Polyline> polylines;
1642
1642
  for (const auto& polyline : lhs) polylines.emplace_back(polyline);
1643
1643
  for (const auto& polyline : rhs) polylines.emplace_back(polyline);
1644
- return Polygon(&polylines[0], polylines.size());
1644
+ return Polygon(polylines.data(), polylines.size());
1645
1645
  }
1646
1646
 
1647
1647
  Polygon
data/src/polyline.cpp CHANGED
@@ -129,7 +129,7 @@ namespace Rays
129
129
 
130
130
  Polyline pl;
131
131
  pl.self->reset(
132
- &cleaned[0], NULL, NULL, cleaned.size(), loop, loop, hole,
132
+ cleaned.data(), NULL, NULL, cleaned.size(), loop, loop, hole,
133
133
  [](const IntPoint& point) {return from_clipper(point);});
134
134
  return pl;
135
135
  }
@@ -224,21 +224,21 @@ namespace Rays
224
224
  Polyline::points () const
225
225
  {
226
226
  const auto& v = self->points;
227
- return !v.empty() ? &v[0] : NULL;
227
+ return !v.empty() ? v.data() : NULL;
228
228
  }
229
229
 
230
230
  const Color*
231
231
  Polyline::colors () const
232
232
  {
233
233
  const auto& pv = self->pcolors;
234
- return pv && !pv->empty() ? &(*pv)[0] : NULL;
234
+ return pv && !pv->empty() ? pv->data() : NULL;
235
235
  }
236
236
 
237
237
  const Coord3*
238
238
  Polyline::texcoords () const
239
239
  {
240
240
  const auto& pv = self->ptexcoords;
241
- return pv && !pv->empty() ? &(*pv)[0] : NULL;
241
+ return pv && !pv->empty() ? pv->data() : NULL;
242
242
  }
243
243
 
244
244
  size_t
data/src/sdl/bitmap.cpp CHANGED
@@ -6,6 +6,7 @@
6
6
  #define STB_IMAGE_WRITE_IMPLEMENTATION
7
7
  #include <stb_image_write.h>
8
8
 
9
+ #include <memory>
9
10
  #include <SDL.h>
10
11
  #include <xot/util.h>
11
12
  #include "rays/exception.h"
@@ -157,11 +158,11 @@ namespace Rays
157
158
  const auto& cs = bitmap.color_space();
158
159
  int w = bitmap.width();
159
160
  int h = bitmap.height();
160
- int pitch = w * cs.Bpp();
161
+ int row_size = w * cs.Bpp();
161
162
 
162
- std::unique_ptr<uchar[]> pixels(new uchar[h * pitch]);
163
+ std::unique_ptr<uchar[]> pixels(new uchar[h * row_size]);
163
164
  for (int y = 0; y < h; ++y)
164
- memcpy(pixels.get() + pitch * y, bitmap.at<uchar>(0, y), pitch);
165
+ memcpy(pixels.get() + row_size * y, bitmap.at<uchar>(0, y), row_size);
165
166
 
166
167
  String ext = extension;
167
168
  ext.downcase();
@@ -196,6 +197,10 @@ namespace Rays
196
197
  p.end();
197
198
  bmp = img.bitmap();
198
199
  }
200
+
201
+ if (bmp.color_space().has_alpha())
202
+ bmp = bmp.dup(false);// stb_image_write expects straight alpha
203
+
199
204
  save_bitmap(bmp, path);
200
205
  }
201
206
 
@@ -206,16 +211,17 @@ namespace Rays
206
211
  argument_error(__FILE__, __LINE__);
207
212
 
208
213
  int w = 0, h = 0, Bpp = 0;
209
- uchar* pixels = stbi_load(path, &w, &h, &Bpp, 0);
214
+ std::unique_ptr<uchar, decltype(&stbi_image_free)>
215
+ pixels(stbi_load(path, &w, &h, &Bpp, 0), stbi_image_free);
210
216
  if (!pixels)
211
217
  rays_error(__FILE__, __LINE__, "failed to load: '%s'", path);
212
218
 
213
219
  ColorSpace cs;
214
220
  switch (Bpp)
215
221
  {
216
- case 1: cs = GRAY_8; break;
217
- case 3: cs = RGB_888; break;
218
- case 4: cs = RGBA_8888; break;
222
+ case 1: cs = GRAY_8; break;
223
+ case 3: cs = RGB_888; break;
224
+ case 4: cs = ColorSpace(RGBA_8888, false); break;// stb_image gives straight alpha
219
225
  default:
220
226
  rays_error(__FILE__, __LINE__, "unsupported image file: '%s'", path);
221
227
  }
@@ -224,11 +230,11 @@ namespace Rays
224
230
  if (!bmp)
225
231
  rays_error(__FILE__, __LINE__, "failed to create Bitmap object");
226
232
 
227
- int pitch = Bpp * w;
233
+ int size = Bpp * w;
228
234
  for (int y = 0; y < h; ++y)
229
- memcpy(bmp.at<uchar>(0, y), pixels + pitch * y, pitch);
235
+ memcpy(bmp.at<uchar>(0, y), pixels.get() + size * y, size);
230
236
 
231
- return bmp;
237
+ return cs.has_alpha() ? bmp.dup(true) : bmp;
232
238
  }
233
239
 
234
240