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/font.cpp CHANGED
@@ -3,6 +3,8 @@
3
3
 
4
4
  #include <string.h>
5
5
  #include <assert.h>
6
+ #include <algorithm>
7
+ #include "rays/exception.h"
6
8
 
7
9
 
8
10
  namespace Rays
@@ -12,53 +14,109 @@ namespace Rays
12
14
  struct Font::Data
13
15
  {
14
16
 
15
- RawFont rawfont;
17
+ String name, path;
18
+
19
+ coord size = 0;
20
+
21
+ int weight = Font::DEFAULT_WEIGHT;
22
+
23
+ bool italic = false;
16
24
 
17
25
  bool smooth = true;
18
26
 
27
+ RawFont rawfont;
28
+
19
29
  mutable RawFont rawfont_for_pixel_density;
20
30
 
21
31
  mutable float for_pixel_density = 1;
22
32
 
23
- const RawFont& get_raw (float pixel_density) const
33
+ RawFont make_rawfont (coord size) const
24
34
  {
25
- assert(pixel_density > 0);
26
-
27
- if (!rawfont || pixel_density == 1)
28
- return rawfont;
35
+ if (!path.empty())
36
+ return RawFont_load(path.c_str(), size);
37
+ else
38
+ return RawFont(name.empty() ? NULL : name.c_str(), size, weight, italic);
39
+ }
29
40
 
30
- if (pixel_density != for_pixel_density)
31
- {
32
- rawfont_for_pixel_density =
33
- RawFont(rawfont, rawfont.size() * pixel_density);
34
- for_pixel_density = pixel_density;
35
- }
41
+ void remake_rawfont ()
42
+ {
43
+ if (!rawfont) return;
36
44
 
37
- return rawfont_for_pixel_density;
45
+ rawfont = make_rawfont(size);
46
+ for_pixel_density = 1;// drop the cache
38
47
  }
39
48
 
40
49
  };// Font::Data
41
50
 
42
51
 
52
+ static int
53
+ clamp_weight (int weight)
54
+ {
55
+ return std::clamp(weight, (int) Font::WEIGHT_MIN, (int) Font::WEIGHT_MAX);
56
+ }
57
+
43
58
  Font
44
59
  load_font (const char* path, coord size)
45
60
  {
46
61
  Font font;
62
+ font.self->path = path ? path : "";
63
+ font.self->size = size;
47
64
  font.self->rawfont = RawFont_load(path, size);
48
65
  return font;
49
66
  }
50
67
 
51
- const Font&
68
+ static constexpr const char* NULL_NAME = "";
69
+
70
+ Font
52
71
  get_default_font ()
53
72
  {
54
- static const Font FONT(NULL);
55
- return FONT;
73
+ static const Font FONT(NULL_NAME);
74
+ return FONT.dup();
56
75
  }
57
76
 
58
77
  const RawFont&
59
78
  Font_get_raw (const Font& font, float pixel_density)
60
79
  {
61
- return font.self->get_raw(pixel_density);
80
+ if (pixel_density <= 0)
81
+ argument_error(__FILE__, __LINE__);
82
+
83
+ Font::Data* self = font.self.get();
84
+
85
+ if (!self->rawfont || pixel_density == 1)
86
+ return self->rawfont;
87
+
88
+ if (pixel_density != self->for_pixel_density)
89
+ {
90
+ self->rawfont_for_pixel_density = self->make_rawfont(self->size * pixel_density);
91
+ self->for_pixel_density = pixel_density;
92
+ }
93
+
94
+ return self->rawfont_for_pixel_density;
95
+ }
96
+
97
+ bool
98
+ Font_has_same_attributes (
99
+ const Font& font, const char* name, coord size,
100
+ int weight, bool italic, bool smooth)
101
+ {
102
+ if (!font.self->path.empty())
103
+ return false;
104
+
105
+ weight = clamp_weight(weight);
106
+
107
+ if (
108
+ size != font.size() ||
109
+ weight != font.weight() ||
110
+ italic != font.italic() ||
111
+ smooth != font.smooth())
112
+ {
113
+ return false;
114
+ }
115
+
116
+ if (!name)
117
+ name = NULL_NAME;
118
+
119
+ return name == font.name(false) || name == font.name(true);
62
120
  }
63
121
 
64
122
 
@@ -66,10 +124,14 @@ namespace Rays
66
124
  {
67
125
  }
68
126
 
69
- Font::Font (const char* name, coord size, bool smooth)
127
+ Font::Font (const char* name, coord size, int weight, bool italic, bool smooth)
70
128
  {
71
- self->rawfont = RawFont(name, size);
129
+ self->name = name ? name : NULL_NAME;
130
+ self->size = size;
131
+ self->weight = clamp_weight(weight);
132
+ self->italic = italic;
72
133
  self->smooth = smooth;
134
+ self->rawfont = self->make_rawfont(size);
73
135
  }
74
136
 
75
137
  Font::~Font ()
@@ -80,27 +142,61 @@ namespace Rays
80
142
  Font::dup () const
81
143
  {
82
144
  Font f;
83
- f.self->rawfont = RawFont(self->rawfont, self->rawfont.size());
84
- f.self->smooth = self->smooth;
145
+ *f.self = *self;
85
146
  return f;
86
147
  }
87
148
 
88
149
  String
89
- Font::name () const
150
+ Font::name (bool resolved) const
90
151
  {
91
- return self->rawfont.name();
152
+ return resolved || self->name.empty() ? self->rawfont.name() : self->name;
92
153
  }
93
154
 
94
155
  void
95
156
  Font::set_size (coord size)
96
157
  {
97
- self->rawfont = RawFont(self->rawfont, size);
158
+ if (size == self->size) return;
159
+
160
+ self->size = size;
161
+ self->remake_rawfont();
98
162
  }
99
163
 
100
164
  coord
101
165
  Font::size () const
102
166
  {
103
- return self->rawfont.size();
167
+ return self->size;
168
+ }
169
+
170
+ void
171
+ Font::set_weight (int weight)
172
+ {
173
+ weight = clamp_weight(weight);
174
+
175
+ if (weight == self->weight) return;
176
+
177
+ self->weight = weight;
178
+ self->remake_rawfont();
179
+ }
180
+
181
+ int
182
+ Font::weight () const
183
+ {
184
+ return self->weight;
185
+ }
186
+
187
+ void
188
+ Font::set_italic (bool italic)
189
+ {
190
+ if (italic == self->italic) return;
191
+
192
+ self->italic = italic;
193
+ self->remake_rawfont();
194
+ }
195
+
196
+ bool
197
+ Font::italic () const
198
+ {
199
+ return self->italic;
104
200
  }
105
201
 
106
202
  void
data/src/font.h CHANGED
@@ -21,9 +21,9 @@ namespace Rays
21
21
 
22
22
  RawFont ();
23
23
 
24
- RawFont (const char* name, coord size);
25
-
26
- RawFont (const This& obj, coord size);
24
+ RawFont (
25
+ const char* name, coord size,
26
+ int weight = Font::DEFAULT_WEIGHT, bool italic = false);
27
27
 
28
28
  ~RawFont ();
29
29
 
@@ -33,8 +33,6 @@ namespace Rays
33
33
 
34
34
  String name () const;
35
35
 
36
- coord size () const;
37
-
38
36
  coord get_width (const char* str) const;
39
37
 
40
38
  coord get_height (
@@ -55,6 +53,10 @@ namespace Rays
55
53
 
56
54
  const RawFont& Font_get_raw (const Font& font, float pixel_density);
57
55
 
56
+ bool Font_has_same_attributes (
57
+ const Font& font, const char* name, coord size,
58
+ int weight, bool italic, bool smooth);
59
+
58
60
 
59
61
  RawFont RawFont_load (const char* path, coord size);
60
62
 
data/src/image.cpp CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include <math.h>
5
5
  #include <assert.h>
6
+ #include <memory>
6
7
  #include "rays/exception.h"
7
8
  #include "rays/debug.h"
8
9
  #include "bitmap.h"
@@ -10,7 +11,7 @@
10
11
 
11
12
 
12
13
  #if 0
13
- #define PRINT_MODIFIED_FLAGS(message) get_data(this)->print_modified_flags(message)
14
+ #define PRINT_MODIFIED_FLAGS(message) self->print_modified_flags(message)
14
15
  #else
15
16
  #define PRINT_MODIFIED_FLAGS(message)
16
17
  #endif
@@ -20,7 +21,19 @@ namespace Rays
20
21
  {
21
22
 
22
23
 
23
- struct ImageData : Image::Data
24
+ struct Pixels
25
+ {
26
+
27
+ typedef std::shared_ptr<Pixels> Ptr;
28
+
29
+ mutable Bitmap bitmap;
30
+
31
+ mutable Texture texture;
32
+
33
+ };// Pixels
34
+
35
+
36
+ struct Image::Data
24
37
  {
25
38
 
26
39
  int width = 0, height = 0;
@@ -31,50 +44,52 @@ namespace Rays
31
44
 
32
45
  ColorSpace color_space;
33
46
 
34
- mutable Bitmap bitmap;
47
+ Pixels::Ptr pixels;
35
48
 
36
- mutable Texture texture;
49
+ std::unique_ptr<Image::Loader> loader;
50
+
51
+ Data ()
52
+ : pixels(new Pixels())
53
+ {
54
+ }
37
55
 
38
56
  void print_modified_flags (const char* message)
39
57
  {
40
58
  printf("%s: %d %d %d %d \n",
41
59
  message,
42
- bitmap ? 1 : 0,
43
- Bitmap_get_modified(bitmap) ? 1 : 0,
44
- texture ? 1 : 0,
45
- texture.modified() ? 1 : 0);
60
+ pixels->bitmap ? 1 : 0,
61
+ Bitmap_get_modified(pixels->bitmap) ? 1 : 0,
62
+ pixels->texture ? 1 : 0,
63
+ pixels->texture.modified() ? 1 : 0);
46
64
  }
47
65
 
48
66
  };// Image::Data
49
67
 
50
68
 
51
- static ImageData*
52
- get_data (Image* image)
53
- {
54
- return (ImageData*) image->self.get();
55
- }
56
-
57
- static const ImageData*
58
- get_data (const Image* image)
59
- {
60
- return (const ImageData*) image->self.get();
61
- }
62
-
63
-
64
69
  static void
65
70
  clear_modified_flags (Image* image)
66
71
  {
67
- ImageData* self = get_data(image);
72
+ Pixels* pixels = image->self->pixels.get();
68
73
 
69
- if (self->bitmap) Bitmap_set_modified(&self->bitmap, false);
70
- if (self->texture) self->texture.set_modified(false);
74
+ if (pixels->bitmap)
75
+ Bitmap_set_modified(&pixels->bitmap, false);
76
+
77
+ if (pixels->texture)
78
+ pixels->texture.set_modified(false);
71
79
  }
72
80
 
73
81
  static void
74
82
  invalidate_texture (Image* image)
75
83
  {
76
84
  image->bitmap();// update bitmap
77
- get_data(image)->texture = Texture();
85
+ image->self->pixels->texture = Texture();
86
+ }
87
+
88
+ static void
89
+ check_writable (const Image* image)
90
+ {
91
+ if (image->self->loader)
92
+ invalid_state_error(__FILE__, __LINE__, "image is read-only");
78
93
  }
79
94
 
80
95
  static Bitmap&
@@ -82,31 +97,32 @@ namespace Rays
82
97
  {
83
98
  assert(image);
84
99
 
85
- ImageData* self = get_data(image);
100
+ Image::Data* self = image->self.get();
101
+ Pixels* pixels = self->pixels.get();
86
102
 
87
103
  if (!*image)
88
104
  {
89
- assert(!self->bitmap);
90
- return self->bitmap;
105
+ assert(!pixels->bitmap);
106
+ return pixels->bitmap;
91
107
  }
92
108
 
93
- if (!self->bitmap)
109
+ if (!pixels->bitmap)
94
110
  {
95
- if (self->texture)
111
+ if (pixels->texture)
96
112
  {
97
113
  PRINT_MODIFIED_FLAGS("new bitmap from texture");
98
- self->bitmap = Bitmap_from(self->texture);
114
+ pixels->bitmap = Bitmap_from(pixels->texture);
99
115
  }
100
116
  else
101
117
  {
102
118
  PRINT_MODIFIED_FLAGS("new bitmap");
103
- self->bitmap = Bitmap(self->width, self->height, self->color_space);
119
+ pixels->bitmap = Bitmap(self->width, self->height, self->color_space);
104
120
  }
105
121
  clear_modified_flags(image);
106
122
  }
107
- else if (self->texture && self->texture.modified())
123
+ else if (pixels->texture && pixels->texture.modified())
108
124
  {
109
- if (Bitmap_get_modified(self->bitmap))
125
+ if (Bitmap_get_modified(pixels->bitmap))
110
126
  {
111
127
  invalid_state_error(
112
128
  __FILE__, __LINE__, "bitmap and texture modifications conflicted");
@@ -114,36 +130,42 @@ namespace Rays
114
130
  else
115
131
  {
116
132
  PRINT_MODIFIED_FLAGS("bitmap from texture");
117
- self->bitmap = Bitmap_from(self->texture);
133
+ pixels->bitmap = Bitmap_from(pixels->texture);
118
134
  clear_modified_flags(image);
119
135
  }
120
136
  }
121
137
 
122
- return self->bitmap;
138
+ if (self->loader && self->loader->load(&pixels->bitmap))
139
+ Bitmap_set_modified(&pixels->bitmap);
140
+
141
+ return pixels->bitmap;
123
142
  }
124
143
 
125
144
  Texture&
126
145
  Image_get_texture (Image& image)
127
146
  {
128
- ImageData* self = get_data(&image);
147
+ Image::Data* self = image.self.get();
148
+ Pixels* pixels = self->pixels.get();
129
149
 
130
150
  if (!image)
131
151
  {
132
- assert(!self->texture);
133
- return self->texture;
152
+ assert(!pixels->texture);
153
+ return pixels->texture;
134
154
  }
135
155
 
136
- if (!self->texture)
156
+ if (self->loader) get_bitmap(&image);
157
+
158
+ if (!pixels->texture)
137
159
  {
138
- if (self->bitmap)
160
+ if (pixels->bitmap)
139
161
  {
140
162
  PRINT_MODIFIED_FLAGS("new texture from bitmap");
141
- self->texture = Texture(self->bitmap, self->smooth);
163
+ pixels->texture = Texture(pixels->bitmap, self->smooth);
142
164
  }
143
165
  else
144
166
  {
145
167
  PRINT_MODIFIED_FLAGS("new texture");
146
- self->texture = Texture(
168
+ pixels->texture = Texture(
147
169
  self->width, self->height, self->color_space, self->smooth);
148
170
 
149
171
  Painter p = image.painter();
@@ -153,9 +175,9 @@ namespace Rays
153
175
  }
154
176
  clear_modified_flags(&image);
155
177
  }
156
- else if (self->bitmap && Bitmap_get_modified(self->bitmap))
178
+ else if (pixels->bitmap && Bitmap_get_modified(pixels->bitmap))
157
179
  {
158
- if (self->texture.modified())
180
+ if (pixels->texture.modified())
159
181
  {
160
182
  invalid_state_error(
161
183
  __FILE__, __LINE__, "texture and bitmap modifications conflicted");
@@ -163,12 +185,12 @@ namespace Rays
163
185
  else
164
186
  {
165
187
  PRINT_MODIFIED_FLAGS("texture from bitmap");
166
- self->texture = self->bitmap;
188
+ pixels->texture = pixels->bitmap;
167
189
  clear_modified_flags(&image);
168
190
  }
169
191
  }
170
192
 
171
- return self->texture;
193
+ return pixels->texture;
172
194
  }
173
195
 
174
196
  const Texture&
@@ -184,30 +206,22 @@ namespace Rays
184
206
  }
185
207
 
186
208
 
187
- Image::Data::~Data ()
188
- {
189
- }
190
-
191
- void
192
- Image::Data::preprocess (const Image*) const
209
+ Image::Loader::~Loader ()
193
210
  {
194
211
  }
195
212
 
196
213
 
197
214
  Image::Image ()
198
- : self(new ImageData())
199
215
  {
200
216
  }
201
217
 
202
218
  Image::Image (
203
219
  int width, int height, const ColorSpace& cs,
204
220
  float pixel_density, bool smooth)
205
- : self(new ImageData())
206
221
  {
207
222
  if (pixel_density <= 0)
208
223
  argument_error(__FILE__, __LINE__, "invalid pixel_density.");
209
224
 
210
- ImageData* self = get_data(this);
211
225
  self->width = (int) (width * pixel_density);
212
226
  self->height = (int) (height * pixel_density);
213
227
  self->color_space = cs;
@@ -216,23 +230,33 @@ namespace Rays
216
230
  }
217
231
 
218
232
  Image::Image (const Bitmap& bitmap, float pixel_density, bool smooth)
219
- : self(new ImageData())
220
233
  {
221
234
  if (pixel_density <= 0)
222
235
  argument_error(__FILE__, __LINE__, "invalid pixel_density.");
223
236
 
224
- ImageData* self = get_data(this);
225
- self->bitmap = bitmap;
226
- self->width = bitmap.width();
227
- self->height = bitmap.height();
228
- self->color_space = bitmap.color_space();
229
- self->pixel_density = pixel_density;
230
- self->smooth = smooth;
237
+ self->pixels->bitmap = bitmap;
238
+ self->width = bitmap.width();
239
+ self->height = bitmap.height();
240
+ self->color_space = bitmap.color_space();
241
+ self->pixel_density = pixel_density;
242
+ self->smooth = smooth;
231
243
  }
232
244
 
233
- Image::Image (Data* data)
234
- : self(data)
245
+ Image::Image (const Image& pixels, Loader* loader)
235
246
  {
247
+ std::unique_ptr<Loader> loader_(loader);
248
+ if (!loader)
249
+ argument_error(__FILE__, __LINE__, "loader is NULL.");
250
+ if (!pixels)
251
+ argument_error(__FILE__, __LINE__, "invalid pixels image.");
252
+
253
+ self->width = pixels.self->width;
254
+ self->height = pixels.self->height;
255
+ self->color_space = pixels.self->color_space;
256
+ self->pixel_density = pixels.self->pixel_density;
257
+ self->smooth = pixels.self->smooth;
258
+ self->pixels = pixels.self->pixels;
259
+ self->loader = std::move(loader_);
236
260
  }
237
261
 
238
262
  Image::~Image ()
@@ -242,16 +266,12 @@ namespace Rays
242
266
  Image
243
267
  Image::dup () const
244
268
  {
245
- self->preprocess(this);
246
-
247
269
  return Image(bitmap().dup(), pixel_density());
248
270
  }
249
271
 
250
272
  void
251
273
  Image::save (const char* path)
252
274
  {
253
- self->preprocess(this);
254
-
255
275
  if (!*this)
256
276
  invalid_state_error(__FILE__, __LINE__);
257
277
 
@@ -261,45 +281,31 @@ namespace Rays
261
281
  coord
262
282
  Image::width () const
263
283
  {
264
- self->preprocess(this);
265
-
266
- const ImageData* self = get_data(this);
267
284
  return self->width / self->pixel_density;
268
285
  }
269
286
 
270
287
  coord
271
288
  Image::height () const
272
289
  {
273
- self->preprocess(this);
274
-
275
- const ImageData* self = get_data(this);
276
290
  return self->height / self->pixel_density;
277
291
  }
278
292
 
279
293
  const ColorSpace&
280
294
  Image::color_space () const
281
295
  {
282
- self->preprocess(this);
283
-
284
- const ImageData* self = get_data(this);
285
296
  return self->color_space;
286
297
  }
287
298
 
288
299
  float
289
300
  Image::pixel_density () const
290
301
  {
291
- self->preprocess(this);
292
-
293
- const ImageData* self = get_data(this);
294
302
  return self->pixel_density;
295
303
  }
296
304
 
297
305
  void
298
306
  Image::set_smooth (bool smooth)
299
307
  {
300
- self->preprocess(this);
301
-
302
- ImageData* self = get_data(this);
308
+ check_writable(this);
303
309
 
304
310
  if (smooth == self->smooth) return;
305
311
  self->smooth = smooth;
@@ -309,16 +315,13 @@ namespace Rays
309
315
  bool
310
316
  Image::smooth () const
311
317
  {
312
- self->preprocess(this);
313
-
314
- const ImageData* self = get_data(this);
315
318
  return self->smooth;
316
319
  }
317
320
 
318
321
  Painter
319
322
  Image::painter ()
320
323
  {
321
- self->preprocess(this);
324
+ check_writable(this);
322
325
 
323
326
  Painter p;
324
327
  p.bind(*this);
@@ -328,15 +331,11 @@ namespace Rays
328
331
  Bitmap&
329
332
  Image::bitmap (bool modify)
330
333
  {
331
- self->preprocess(this);
334
+ if (modify) check_writable(this);
332
335
 
333
- ImageData* self = get_data(this);
334
- if (modify)
335
- {
336
- if (!self->bitmap) get_bitmap(this);
337
- Bitmap_set_modified(&self->bitmap);
338
- }
339
- return get_bitmap(this);
336
+ Bitmap& bitmap = get_bitmap(this);
337
+ if (modify) Bitmap_set_modified(&bitmap);
338
+ return bitmap;
340
339
  }
341
340
 
342
341
  const Bitmap&
@@ -345,11 +344,14 @@ namespace Rays
345
344
  return const_cast<Image*>(this)->bitmap();
346
345
  }
347
346
 
348
- Image::operator bool () const
347
+ const Image::Loader*
348
+ Image::loader () const
349
349
  {
350
- self->preprocess(this);
350
+ return self->loader.get();
351
+ }
351
352
 
352
- const ImageData* self = get_data(this);
353
+ Image::operator bool () const
354
+ {
353
355
  return
354
356
  self->width > 0 &&
355
357
  self->height > 0 &&