rays 0.2 → 0.3

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/rays/bitmap.cpp +100 -33
  3. data/.doc/ext/rays/bounds.cpp +2 -2
  4. data/.doc/ext/rays/camera.cpp +2 -2
  5. data/.doc/ext/rays/color.cpp +2 -2
  6. data/.doc/ext/rays/color_space.cpp +3 -3
  7. data/.doc/ext/rays/font.cpp +5 -4
  8. data/.doc/ext/rays/image.cpp +1 -1
  9. data/.doc/ext/rays/matrix.cpp +4 -4
  10. data/.doc/ext/rays/painter.cpp +1 -1
  11. data/.doc/ext/rays/point.cpp +2 -2
  12. data/.doc/ext/rays/polygon.cpp +3 -3
  13. data/.doc/ext/rays/polyline.cpp +3 -3
  14. data/.doc/ext/rays/rays.cpp +10 -10
  15. data/.doc/ext/rays/shader.cpp +2 -2
  16. data/.github/workflows/release-gem.yml +2 -2
  17. data/.github/workflows/tag.yml +1 -1
  18. data/.github/workflows/test.yml +10 -1
  19. data/ChangeLog.md +14 -0
  20. data/Gemfile.lock +1 -1
  21. data/Rakefile +17 -2
  22. data/VERSION +1 -1
  23. data/ext/rays/bitmap.cpp +100 -33
  24. data/ext/rays/bounds.cpp +2 -2
  25. data/ext/rays/camera.cpp +2 -2
  26. data/ext/rays/color.cpp +2 -2
  27. data/ext/rays/color_space.cpp +3 -3
  28. data/ext/rays/defs.h +2 -0
  29. data/ext/rays/extconf.rb +4 -2
  30. data/ext/rays/font.cpp +5 -4
  31. data/ext/rays/image.cpp +1 -1
  32. data/ext/rays/matrix.cpp +4 -4
  33. data/ext/rays/painter.cpp +1 -1
  34. data/ext/rays/point.cpp +2 -2
  35. data/ext/rays/polygon.cpp +3 -3
  36. data/ext/rays/polyline.cpp +3 -3
  37. data/ext/rays/rays.cpp +10 -10
  38. data/ext/rays/shader.cpp +2 -2
  39. data/include/rays/color_space.h +4 -4
  40. data/include/rays/defs.h +7 -0
  41. data/include/rays/rays.h +8 -0
  42. data/include/rays/ruby/bitmap.h +2 -2
  43. data/include/rays/ruby/bounds.h +2 -2
  44. data/include/rays/ruby/camera.h +2 -2
  45. data/include/rays/ruby/color.h +2 -2
  46. data/include/rays/ruby/color_space.h +2 -2
  47. data/include/rays/ruby/exception.h +3 -3
  48. data/include/rays/ruby/font.h +2 -2
  49. data/include/rays/ruby/image.h +2 -2
  50. data/include/rays/ruby/matrix.h +2 -2
  51. data/include/rays/ruby/painter.h +2 -2
  52. data/include/rays/ruby/point.h +2 -2
  53. data/include/rays/ruby/polygon.h +2 -2
  54. data/include/rays/ruby/polyline.h +2 -2
  55. data/include/rays/ruby/rays.h +6 -6
  56. data/include/rays/ruby/shader.h +2 -2
  57. data/include/rays/ruby.h +3 -1
  58. data/include/rays.h +3 -0
  59. data/lib/rays/bitmap.rb +7 -0
  60. data/lib/rays/extension.rb +4 -0
  61. data/rays.gemspec +2 -2
  62. data/src/coord.h +2 -2
  63. data/src/font.cpp +1 -0
  64. data/src/image.cpp +0 -29
  65. data/src/ios/bitmap.mm +23 -30
  66. data/src/ios/font.mm +4 -1
  67. data/src/ios/opengl.mm +23 -10
  68. data/src/ios/rays.mm +5 -3
  69. data/src/matrix.h +1 -1
  70. data/src/opengl.h +7 -8
  71. data/src/osx/bitmap.mm +23 -30
  72. data/src/osx/font.mm +4 -1
  73. data/src/osx/opengl.mm +31 -19
  74. data/src/osx/rays.mm +5 -3
  75. data/src/painter.cpp +1 -0
  76. data/src/shader.cpp +3 -0
  77. data/src/texture.cpp +3 -25
  78. data/src/texture.h +0 -2
  79. data/src/win32/bitmap.cpp +167 -65
  80. data/src/win32/camera.cpp +119 -0
  81. data/src/win32/font.cpp +179 -40
  82. data/src/win32/gdi.cpp +2 -4
  83. data/src/win32/gdi.h +1 -1
  84. data/src/win32/opengl.cpp +127 -0
  85. data/src/win32/rays.cpp +16 -9
  86. data/test/helper.rb +2 -5
  87. data/test/test_bitmap.rb +3 -1
  88. data/test/test_image.rb +8 -14
  89. data/test/test_painter.rb +4 -4
  90. metadata +8 -8
  91. data/include/rays/opengl.h +0 -20
  92. data/src/win32/font.h +0 -24
data/src/osx/bitmap.mm CHANGED
@@ -2,7 +2,6 @@
2
2
  #import "bitmap.h"
3
3
 
4
4
 
5
- #include <assert.h>
6
5
  #import <Cocoa/Cocoa.h>
7
6
  #include "rays/exception.h"
8
7
  #include "../color_space.h"
@@ -60,7 +59,7 @@ namespace Rays
60
59
 
61
60
  ColorSpace color_space;
62
61
 
63
- void* pixels = NULL;
62
+ void* pixels = NULL;
64
63
 
65
64
  CGContextRef context = NULL;
66
65
 
@@ -122,37 +121,40 @@ namespace Rays
122
121
 
123
122
  static void
124
123
  setup_bitmap (
125
- Bitmap* this_,
124
+ Bitmap* bitmap,
126
125
  int w, int h, const ColorSpace& cs,
127
- const void* pixels_ = NULL, bool clear_pixels = true)
126
+ const void* pixels = NULL, bool clear_pixels = true)
128
127
  {
129
- if (!this_ || w <= 0 || h <= 0 || !cs)
128
+ if (w <= 0 || h <= 0 || !cs)
130
129
  argument_error(__FILE__, __LINE__);
131
130
 
132
- this_->self->clear();
131
+ Bitmap::Data* self = bitmap->self.get();
133
132
 
134
- this_->self->width = w;
135
- this_->self->height = h;
136
- this_->self->color_space = cs;
137
- this_->self->modified = true;
133
+ self->clear();
134
+
135
+ self->width = w;
136
+ self->height = h;
137
+ self->color_space = cs;
138
+ self->modified = true;
138
139
 
139
140
  size_t size = w * h * cs.Bpp();
140
- this_->self->pixels = new uchar[size];
141
+ self->pixels = new uchar[size];
141
142
 
142
- if (pixels_)
143
- memcpy(this_->self->pixels, pixels_, size);
143
+ if (pixels)
144
+ memcpy(self->pixels, pixels, size);
144
145
  else if (clear_pixels)
145
- memset(this_->self->pixels, 0, size);
146
+ memset(self->pixels, 0, size);
146
147
  }
147
148
 
148
- static void
149
- setup_bitmap (Bitmap* this_, const Texture& tex)
149
+ Bitmap
150
+ Bitmap_from (const Texture& tex)
150
151
  {
151
- if (!this_ || !tex)
152
+ if (!tex)
152
153
  argument_error(__FILE__, __LINE__);
153
154
 
155
+ Bitmap bmp;
154
156
  setup_bitmap(
155
- this_, tex.width(), tex.height(), tex.color_space(), NULL, false);
157
+ &bmp, tex.width(), tex.height(), tex.color_space(), NULL, false);
156
158
 
157
159
  GLenum format, type;
158
160
  ColorSpace_get_gl_format_and_type(&format, &type, tex.color_space());
@@ -160,18 +162,12 @@ namespace Rays
160
162
  FrameBuffer fb(tex);
161
163
  FrameBufferBinder binder(fb.id());
162
164
 
163
- for (int y = 0; y < this_->height(); ++y)
165
+ for (int y = 0; y < bmp.height(); ++y)
164
166
  {
165
- GLvoid* ptr = (GLvoid*) this_->at<uchar>(0, y);
166
- glReadPixels(0, y, this_->width(), 1, format, type, ptr);
167
+ GLvoid* ptr = (GLvoid*) bmp.at<uchar>(0, y);
168
+ glReadPixels(0, y, bmp.width(), 1, format, type, ptr);
167
169
  }
168
- }
169
170
 
170
- Bitmap
171
- Bitmap_from (const Texture& texture)
172
- {
173
- Bitmap bmp;
174
- setup_bitmap(&bmp, texture);
175
171
  return bmp;
176
172
  }
177
173
 
@@ -206,15 +202,12 @@ namespace Rays
206
202
  if (*str == '\0') return;
207
203
 
208
204
  font.draw_string(bitmap->self->get_context(), bitmap->height(), str, x, y);
209
-
210
205
  Bitmap_set_modified(bitmap);
211
206
  }
212
207
 
213
208
  void
214
209
  Bitmap_set_modified (Bitmap* bitmap, bool modified)
215
210
  {
216
- assert(bitmap);
217
-
218
211
  bitmap->self->modified = modified;
219
212
  }
220
213
 
data/src/osx/font.mm CHANGED
@@ -154,11 +154,14 @@ namespace Rays
154
154
  {
155
155
  CGContextRef context = (CGContextRef) context_;
156
156
 
157
- if (!*this || !context || !str)
157
+ if (!context || !str)
158
158
  argument_error(__FILE__, __LINE__);
159
159
 
160
160
  if (*str == '\0') return;
161
161
 
162
+ if (!*this)
163
+ invalid_state_error(__FILE__, __LINE__);
164
+
162
165
  CTLinePtr line = make_line(self->font, str);
163
166
  if (!line)
164
167
  rays_error(__FILE__, __LINE__, "creating CTLineRef failed.");
data/src/osx/opengl.mm CHANGED
@@ -3,30 +3,18 @@
3
3
 
4
4
 
5
5
  #import <AppKit/AppKit.h>
6
+ #include "rays/rays.h"
7
+ #include "rays/exception.h"
6
8
 
7
9
 
8
10
  namespace Rays
9
11
  {
10
12
 
11
13
 
12
- void
13
- OpenGL_set_context (Context context)
14
- {
15
- NSOpenGLContext* c = (NSOpenGLContext*) context;
16
- [c makeCurrentContext];
17
- }
18
-
19
- Context
20
- OpenGL_get_context ()
14
+ static NSOpenGLContext*
15
+ get_opengl_offscreen_context ()
21
16
  {
22
- return [NSOpenGLContext currentContext];
23
- }
24
-
25
-
26
- Context
27
- get_offscreen_context ()
28
- {
29
- static Context context = NULL;
17
+ static NSOpenGLContext* context = nil;
30
18
  if (!context)
31
19
  {
32
20
  NSOpenGLPixelFormatAttribute attribs[] =
@@ -44,11 +32,35 @@ namespace Rays
44
32
  };
45
33
  NSOpenGLPixelFormat* pf = [[[NSOpenGLPixelFormat alloc]
46
34
  initWithAttributes: attribs] autorelease];
47
- context = [[[NSOpenGLContext alloc]
48
- initWithFormat: pf shareContext: nil] autorelease];
35
+ context = [[NSOpenGLContext alloc] initWithFormat: pf shareContext: nil];
49
36
  }
50
37
  return context;
51
38
  }
52
39
 
53
40
 
41
+ void
42
+ OpenGL_init ()
43
+ {
44
+ activate_offscreen_context();
45
+ }
46
+
47
+ void
48
+ OpenGL_fin ()
49
+ {
50
+ }
51
+
52
+
53
+ Context
54
+ get_offscreen_context ()
55
+ {
56
+ return get_opengl_offscreen_context();
57
+ }
58
+
59
+ void
60
+ activate_offscreen_context ()
61
+ {
62
+ [get_opengl_offscreen_context() makeCurrentContext];
63
+ }
64
+
65
+
54
66
  }// Rays
data/src/osx/rays.mm CHANGED
@@ -25,18 +25,20 @@ namespace Rays
25
25
  init ()
26
26
  {
27
27
  if (global::pool)
28
- rays_error(__FILE__, __LINE__, "Rays::init(): already initialized.");
28
+ rays_error(__FILE__, __LINE__, "already initialized.");
29
29
 
30
30
  global::pool = [[NSAutoreleasePool alloc] init];
31
31
 
32
- OpenGL_set_context(get_offscreen_context());
32
+ OpenGL_init();
33
33
  }
34
34
 
35
35
  void
36
36
  fin ()
37
37
  {
38
38
  if (!global::pool)
39
- rays_error(__FILE__, __LINE__, "Rays::fin(): not initialized.");
39
+ rays_error(__FILE__, __LINE__, "not initialized.");
40
+
41
+ OpenGL_fin();
40
42
 
41
43
  [global::pool release];
42
44
  global::pool = nil;
data/src/painter.cpp CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
 
4
4
  #include <math.h>
5
+ #include <string.h>
5
6
  #include <assert.h>
6
7
  #include <memory>
7
8
  #include <vector>
data/src/shader.cpp CHANGED
@@ -156,6 +156,9 @@ namespace Rays
156
156
  // restore premultiplied rgb values
157
157
  " vec3 rgb__ = col__.a != 0.0 ? col__.rgb / col__.a : col__.rgb;\n"
158
158
  " gl_FragColor = " + V_COLOR + " * vec4(rgb__, col__.a);\n"
159
+ #elif defined(WIN32)
160
+ " float a__ = (col__.r + col__.g + col__.b) / 3.0;\n"
161
+ " gl_FragColor = " + V_COLOR + " * vec4(1.0, 1.0, 1.0, a__);\n"
159
162
  #else
160
163
  " gl_FragColor = " + V_COLOR + " * col__;\n"
161
164
  #endif
data/src/texture.cpp CHANGED
@@ -17,8 +17,6 @@ namespace Rays
17
17
  struct Texture::Data
18
18
  {
19
19
 
20
- Context context = NULL;
21
-
22
20
  GLuint id = 0;
23
21
 
24
22
  int width, height, width_pow2, height_pow2;
@@ -53,22 +51,15 @@ namespace Rays
53
51
  {
54
52
  if (!has_id()) return;
55
53
 
56
- Context current_context = OpenGL_get_context();
57
-
58
- assert(context);
59
- OpenGL_set_context(context);
60
-
61
54
  glDeleteTextures(1, &id);
55
+ OpenGL_check_error(__FILE__, __LINE__);
62
56
 
63
- OpenGL_set_context(current_context);
64
-
65
- context = NULL;
66
- id = 0;
57
+ id = 0;
67
58
  }
68
59
 
69
60
  bool has_id () const
70
61
  {
71
- return context && id > 0;
62
+ return id > 0;
72
63
  }
73
64
 
74
65
  };// Texture::Data
@@ -185,13 +176,6 @@ namespace Rays
185
176
  {
186
177
  assert(self && !self->has_id());
187
178
 
188
- if (self->context)
189
- invalid_state_error(__FILE__, __LINE__);
190
-
191
- self->context = OpenGL_get_context();
192
- if (!self->context)
193
- opengl_error(__FILE__, __LINE__);
194
-
195
179
  glGenTextures(1, &self->id);
196
180
  glBindTexture(GL_TEXTURE_2D, self->id);
197
181
  if (glIsTexture(self->id) == GL_FALSE)
@@ -313,12 +297,6 @@ namespace Rays
313
297
  return self->color_space;
314
298
  }
315
299
 
316
- Context
317
- Texture::context () const
318
- {
319
- return self->context;
320
- }
321
-
322
300
  GLuint
323
301
  Texture::id () const
324
302
  {
data/src/texture.h CHANGED
@@ -42,8 +42,6 @@ namespace Rays
42
42
 
43
43
  const ColorSpace& color_space () const;
44
44
 
45
- Context context () const;
46
-
47
45
  GLuint id () const;
48
46
 
49
47
  void set_modified (bool modified = true);
data/src/win32/bitmap.cpp CHANGED
@@ -1,8 +1,16 @@
1
1
  #include "../bitmap.h"
2
2
 
3
3
 
4
- #include <assert.h>
5
- #include "font.h"
4
+ #define STB_IMAGE_IMPLEMENTATION
5
+ #include <stb_image.h>
6
+ #define STB_IMAGE_WRITE_IMPLEMENTATION
7
+ #include <stb_image_write.h>
8
+
9
+ #include "rays/exception.h"
10
+ #include "../color_space.h"
11
+ #include "../font.h"
12
+ #include "../texture.h"
13
+ #include "../frame_buffer.h"
6
14
  #include "gdi.h"
7
15
 
8
16
 
@@ -15,60 +23,55 @@ namespace Rays
15
23
 
16
24
  int width, height, pitch;
17
25
 
18
- ColorSpace colorspace;
26
+ ColorSpace color_space;
19
27
 
20
- void* pixels;
28
+ void* pixels = NULL;
21
29
 
22
30
  Win32::MemoryDC memdc;
23
31
 
24
32
  bool modified;
25
33
 
26
34
  Data ()
27
- : pixels(NULL), modified(true)
28
35
  {
36
+ clear();
29
37
  }
30
38
 
31
- };// Window::Data
32
-
33
-
34
- static bool
35
- init_bitmap_pixels (Bitmap* bmp)
36
- {
37
- if (!*bmp) return false;
38
-
39
- memset(bmp->data(), 0, bmp->size());
40
-
41
- if (!bmp->color_space().has_alpha())
42
- return true;
39
+ ~Data ()
40
+ {
41
+ clear();
42
+ }
43
43
 
44
- int Bpp = bmp->color_space().Bpp();
45
- for (int y = 0; y < bmp->height(); ++y)
44
+ void clear ()
46
45
  {
47
- unsigned char* p =
48
- bmp->at<unsigned char>(0, y) + bmp->color_space().alpha_pos();
49
- int w = bmp->width();
50
- while (w--)
51
- {
52
- *p = 255;
53
- p += Bpp;
54
- }
46
+ if (memdc) memdc = Win32::MemoryDC();
47
+
48
+ width = height = pitch = 0;
49
+ color_space = COLORSPACE_UNKNOWN;
50
+ pixels = NULL;
51
+ modified = false;
55
52
  }
56
53
 
57
- return true;
58
- }
54
+ };// Bitmap::Data
59
55
 
60
- static bool
61
- setup_bitmap (Bitmap* bmp, int w, int h, const ColorSpace& cs, HDC hdc = NULL)
56
+
57
+ static void
58
+ setup_bitmap (
59
+ Bitmap* bitmap,
60
+ int w, int h, const ColorSpace& cs,
61
+ const void* pixels = NULL, bool clear_pixels = true, HDC hdc = NULL)
62
62
  {
63
- if (w <= 0 || h <= 0 || !cs || !bmp || *bmp)
64
- return false;
63
+ if (w <= 0 || h <= 0 || !cs)
64
+ argument_error(__FILE__, __LINE__);
65
+
66
+ Bitmap::Data* self = bitmap->self.get();
65
67
 
66
- Bitmap::Data* self = bmp->self.get();
68
+ self->clear();
67
69
 
68
- self->width = w;
69
- self->height = h;
70
- self->colorspace = cs;
71
- self->pitch = self->width * self->colorspace.Bpp();
70
+ self->width = w;
71
+ self->height = h;
72
+ self->pitch = w * cs.Bpp();
73
+ self->color_space = cs;
74
+ self->modified = true;
72
75
 
73
76
  int padding = 4 - self->pitch % 4;
74
77
  if (padding < 4) self->pitch += padding;
@@ -81,32 +84,49 @@ namespace Rays
81
84
  header.biWidth = self->width;
82
85
  header.biHeight = -self->height;
83
86
  header.biPlanes = 1;
84
- header.biBitCount = self->colorspace.bpp();
87
+ header.biBitCount = self->color_space.bpp();
85
88
  header.biCompression = BI_RGB;
86
89
 
87
90
  Win32::DC dc = hdc ? Win32::DC(hdc) : Win32::screen_dc();
88
91
 
89
92
  HBITMAP hbmp = CreateDIBSection(
90
93
  dc.handle(), &bmpinfo, DIB_RGB_COLORS, (void**) &self->pixels, NULL, 0);
91
- if (!hbmp) return false;
94
+ if (!hbmp)
95
+ rays_error(__FILE__, __LINE__);
92
96
 
93
97
  self->memdc = Win32::MemoryDC(dc.handle(), Win32::Bitmap(hbmp, true));
94
- if (!self->memdc) return false;
95
-
96
- return init_bitmap_pixels(bmp);
97
- }
98
-
99
- static void
100
- setup_bitmap (Bitmap* this_, const Texture& tex)
101
- {
102
- not_implemented_error(__FILE__, __LINE__);
98
+ if (!self->memdc)
99
+ rays_error(__FILE__, __LINE__);
100
+
101
+ size_t size = self->pitch * self->height;
102
+ if (pixels)
103
+ memcpy(self->pixels, pixels, size);
104
+ else if (clear_pixels)
105
+ memset(self->pixels, 0, size);
103
106
  }
104
107
 
105
108
  Bitmap
106
- Bitmap_from (const Texture& texture)
109
+ Bitmap_from (const Texture& tex)
107
110
  {
111
+ if (!tex)
112
+ argument_error(__FILE__, __LINE__);
113
+
108
114
  Bitmap bmp;
109
- setup_bitmap(&bmp, texture);
115
+ setup_bitmap(
116
+ &bmp, tex.width(), tex.height(), tex.color_space(), NULL, false);
117
+
118
+ GLenum format, type;
119
+ ColorSpace_get_gl_format_and_type(&format, &type, tex.color_space());
120
+
121
+ FrameBuffer fb(tex);
122
+ FrameBufferBinder binder(fb.id());
123
+
124
+ for (int y = 0; y < bmp.height(); ++y)
125
+ {
126
+ GLvoid* ptr = (GLvoid*) bmp.at<uchar>(0, y);
127
+ glReadPixels(0, y, bmp.width(), 1, format, type, ptr);
128
+ }
129
+
110
130
  return bmp;
111
131
  }
112
132
 
@@ -126,8 +146,6 @@ namespace Rays
126
146
  void
127
147
  Bitmap_set_modified (Bitmap* bitmap, bool modified)
128
148
  {
129
- assert(bitmap);
130
-
131
149
  bitmap->self->modified = modified;
132
150
  }
133
151
 
@@ -137,16 +155,83 @@ namespace Rays
137
155
  return bitmap.self->modified;
138
156
  }
139
157
 
140
- bool
141
- Bitmap_save (const Bitmap& bitmap, const char* path)
158
+ static const char*
159
+ get_ext (const char* path)
142
160
  {
143
- return false;
161
+ if (!path)
162
+ return NULL;
163
+
164
+ return strrchr(path, '.');
144
165
  }
145
166
 
146
- bool
147
- Bitmap_load (Bitmap* bitmap, const char* path)
167
+ void
168
+ Bitmap_save (const Bitmap& bmp, const char* path)
148
169
  {
149
- return false;
170
+ const char* ext = get_ext(path);
171
+ if (!ext)
172
+ {
173
+ argument_error(
174
+ __FILE__, __LINE__, "invalid image file extension: '%s'", path);
175
+ }
176
+
177
+ const auto& cs = bmp.color_space();
178
+ size_t w = bmp.width();
179
+ size_t h = bmp.height();
180
+ size_t pitch = w * cs.Bpp();
181
+
182
+ std::unique_ptr<uchar[]> pixels(new uchar[h * pitch]);
183
+ for (size_t y = 0; y < h; ++y)
184
+ memcpy(pixels.get() + pitch * y, bmp.at<uchar>(0, y), pitch);
185
+
186
+ int ret = 0;
187
+ if (stricmp(ext, ".bmp") == 0)
188
+ ret = stbi_write_bmp(path, w, h, cs.Bpp(), pixels.get());
189
+ else
190
+ if (stricmp(ext, ".png") == 0)
191
+ ret = stbi_write_png(path, w, h, cs.Bpp(), pixels.get(), 0);
192
+ else
193
+ if (stricmp(ext, ".jpg") == 0 || stricmp(ext, ".jpeg") == 0)
194
+ ret = stbi_write_jpg(path, w, h, cs.Bpp(), pixels.get(), 90);
195
+ else
196
+ if (stricmp(ext, ".tga") == 0)
197
+ ret = stbi_write_tga(path, w, h, cs.Bpp(), pixels.get());
198
+ else
199
+ argument_error(__FILE__, __LINE__, "unknown image file type");
200
+
201
+ if (!ret)
202
+ rays_error(__FILE__, __LINE__, "failed to save: '%s'", path);
203
+ }
204
+
205
+ Bitmap
206
+ Bitmap_load (const char* path)
207
+ {
208
+ if (!path)
209
+ argument_error(__FILE__, __LINE__);
210
+
211
+ int w = 0, h = 0, Bpp = 0;
212
+ uchar* pixels = stbi_load(path, &w, &h, &Bpp, 0);
213
+ if (!pixels)
214
+ rays_error(__FILE__, __LINE__, "failed to load: '%s'", path);
215
+
216
+ ColorSpace cs;
217
+ switch (Bpp)
218
+ {
219
+ case 1: cs = GRAY_8; break;
220
+ case 3: cs = RGB_888; break;
221
+ case 4: cs = RGBA_8888; break;
222
+ default:
223
+ rays_error(__FILE__, __LINE__, "unsupported image file: '%s'", path);
224
+ }
225
+
226
+ Bitmap bmp(w, h, cs);
227
+ if (!bmp)
228
+ rays_error(__FILE__, __LINE__, "failed to create Bitmap object");
229
+
230
+ int pitch = Bpp * w;
231
+ for (int y = 0; y < h; ++y)
232
+ memcpy(bmp.at<uchar>(0, y), pixels + pitch * y, pitch);
233
+
234
+ return bmp;
150
235
  }
151
236
 
152
237
 
@@ -154,31 +239,45 @@ namespace Rays
154
239
  {
155
240
  }
156
241
 
157
- Bitmap::Bitmap (int width, int height, const ColorSpace& cs)
242
+ Bitmap::Bitmap (
243
+ int width, int height, const ColorSpace& color_space, const void* pixels)
158
244
  {
159
- setup_bitmap(this, width, height, cs);
245
+ setup_bitmap(this, width, height, color_space, pixels);
160
246
  }
161
247
 
162
248
  Bitmap::~Bitmap ()
163
249
  {
164
250
  }
165
251
 
252
+ Bitmap
253
+ Bitmap::dup () const
254
+ {
255
+ return Bitmap(width(), height(), color_space(), pixels());
256
+ }
257
+
166
258
  int
167
259
  Bitmap::width () const
168
260
  {
261
+ if (!*this) return 0;
169
262
  return self->width;
170
263
  }
171
264
 
172
265
  int
173
266
  Bitmap::height () const
174
267
  {
268
+ if (!*this) return 0;
175
269
  return self->height;
176
270
  }
177
271
 
178
272
  const ColorSpace&
179
273
  Bitmap::color_space () const
180
274
  {
181
- return self->colorspace;
275
+ if (!*this)
276
+ {
277
+ static const ColorSpace UNKNOWN = COLORSPACE_UNKNOWN;
278
+ return UNKNOWN;
279
+ }
280
+ return self->color_space;
182
281
  }
183
282
 
184
283
  int
@@ -196,6 +295,7 @@ namespace Rays
196
295
  void*
197
296
  Bitmap::pixels ()
198
297
  {
298
+ if (!*this) return NULL;
199
299
  return self->pixels;
200
300
  }
201
301
 
@@ -208,9 +308,11 @@ namespace Rays
208
308
  Bitmap::operator bool () const
209
309
  {
210
310
  return
211
- self &&
212
- self->width > 0 && self->height > 0 && self->pitch > 0 &&
213
- self->colorspace && self->pixels && self->memdc;
311
+ self->width > 0 &&
312
+ self->height > 0 &&
313
+ self->pitch > 0 &&
314
+ self->color_space &&
315
+ self->pixels;
214
316
  }
215
317
 
216
318
  bool