rays 0.1.12 → 0.1.17

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 (168) hide show
  1. checksums.yaml +5 -5
  2. data/.doc/ext/rays/bitmap.cpp +22 -76
  3. data/.doc/ext/rays/bounds.cpp +95 -125
  4. data/.doc/ext/rays/camera.cpp +171 -0
  5. data/.doc/ext/rays/color.cpp +223 -45
  6. data/.doc/ext/rays/color_space.cpp +146 -46
  7. data/.doc/ext/rays/defs.cpp +183 -0
  8. data/.doc/ext/rays/font.cpp +69 -21
  9. data/.doc/ext/rays/image.cpp +26 -37
  10. data/.doc/ext/rays/matrix.cpp +186 -29
  11. data/.doc/ext/rays/native.cpp +14 -8
  12. data/.doc/ext/rays/noise.cpp +53 -0
  13. data/.doc/ext/rays/painter.cpp +187 -292
  14. data/.doc/ext/rays/point.cpp +96 -77
  15. data/.doc/ext/rays/polygon.cpp +313 -0
  16. data/.doc/ext/rays/polygon_line.cpp +96 -0
  17. data/.doc/ext/rays/polyline.cpp +167 -0
  18. data/.doc/ext/rays/rays.cpp +103 -12
  19. data/.doc/ext/rays/shader.cpp +83 -9
  20. data/LICENSE +21 -0
  21. data/README.md +1 -1
  22. data/Rakefile +24 -9
  23. data/VERSION +1 -1
  24. data/ext/rays/bitmap.cpp +23 -81
  25. data/ext/rays/bounds.cpp +100 -128
  26. data/ext/rays/camera.cpp +186 -0
  27. data/ext/rays/color.cpp +231 -51
  28. data/ext/rays/color_space.cpp +149 -47
  29. data/ext/rays/defs.cpp +183 -0
  30. data/ext/rays/defs.h +26 -2
  31. data/ext/rays/extconf.rb +2 -3
  32. data/ext/rays/font.cpp +74 -24
  33. data/ext/rays/image.cpp +28 -40
  34. data/ext/rays/matrix.cpp +198 -30
  35. data/ext/rays/native.cpp +14 -8
  36. data/ext/rays/noise.cpp +55 -0
  37. data/ext/rays/painter.cpp +203 -298
  38. data/ext/rays/point.cpp +105 -81
  39. data/ext/rays/polygon.cpp +329 -0
  40. data/ext/rays/polygon_line.cpp +99 -0
  41. data/ext/rays/polyline.cpp +176 -0
  42. data/ext/rays/rays.cpp +103 -13
  43. data/ext/rays/shader.cpp +84 -9
  44. data/include/rays.h +10 -2
  45. data/include/rays/bitmap.h +14 -26
  46. data/include/rays/bounds.h +21 -4
  47. data/include/rays/camera.h +74 -0
  48. data/include/rays/color.h +25 -14
  49. data/include/rays/color_space.h +15 -10
  50. data/include/rays/coord.h +114 -0
  51. data/include/rays/debug.h +22 -0
  52. data/include/rays/defs.h +36 -0
  53. data/include/rays/exception.h +6 -2
  54. data/include/rays/font.h +4 -4
  55. data/include/rays/image.h +12 -18
  56. data/include/rays/matrix.h +50 -24
  57. data/include/rays/noise.h +42 -0
  58. data/include/rays/opengl.h +2 -50
  59. data/include/rays/painter.h +89 -93
  60. data/include/rays/point.h +44 -51
  61. data/include/rays/polygon.h +198 -0
  62. data/include/rays/polyline.h +71 -0
  63. data/include/rays/rays.h +3 -0
  64. data/include/rays/ruby.h +7 -1
  65. data/include/rays/ruby/bounds.h +1 -1
  66. data/include/rays/ruby/camera.h +41 -0
  67. data/include/rays/ruby/color.h +1 -1
  68. data/include/rays/ruby/color_space.h +1 -1
  69. data/include/rays/ruby/font.h +1 -1
  70. data/include/rays/ruby/matrix.h +1 -1
  71. data/include/rays/ruby/point.h +1 -1
  72. data/include/rays/ruby/polygon.h +52 -0
  73. data/include/rays/ruby/polyline.h +41 -0
  74. data/include/rays/ruby/rays.h +8 -0
  75. data/include/rays/ruby/shader.h +1 -1
  76. data/include/rays/shader.h +36 -8
  77. data/lib/rays.rb +7 -2
  78. data/lib/rays/bitmap.rb +0 -15
  79. data/lib/rays/bounds.rb +17 -23
  80. data/lib/rays/camera.rb +24 -0
  81. data/lib/rays/color.rb +20 -47
  82. data/lib/rays/color_space.rb +13 -13
  83. data/lib/rays/image.rb +3 -7
  84. data/lib/rays/matrix.rb +28 -0
  85. data/lib/rays/module.rb +4 -19
  86. data/lib/rays/painter.rb +78 -93
  87. data/lib/rays/point.rb +13 -21
  88. data/lib/rays/polygon.rb +58 -0
  89. data/lib/rays/polygon_line.rb +36 -0
  90. data/lib/rays/polyline.rb +32 -0
  91. data/lib/rays/shader.rb +20 -1
  92. data/rays.gemspec +5 -7
  93. data/src/bitmap.h +36 -0
  94. data/src/bounds.cpp +74 -11
  95. data/src/color.cpp +58 -23
  96. data/src/color_space.cpp +52 -34
  97. data/src/color_space.h +22 -0
  98. data/src/coord.cpp +170 -0
  99. data/src/coord.h +35 -0
  100. data/src/font.cpp +118 -0
  101. data/src/font.h +64 -0
  102. data/src/frame_buffer.cpp +37 -71
  103. data/src/frame_buffer.h +4 -4
  104. data/src/image.cpp +172 -98
  105. data/src/image.h +25 -0
  106. data/src/ios/bitmap.h +23 -0
  107. data/src/ios/bitmap.mm +133 -110
  108. data/src/ios/camera.mm +510 -0
  109. data/src/ios/font.mm +50 -62
  110. data/src/ios/helper.h +4 -4
  111. data/src/ios/opengl.mm +19 -4
  112. data/src/ios/rays.mm +3 -0
  113. data/src/matrix.cpp +111 -26
  114. data/src/matrix.h +30 -0
  115. data/src/noise.cpp +74 -0
  116. data/src/opengl.cpp +9 -27
  117. data/src/opengl.h +37 -0
  118. data/src/osx/bitmap.h +23 -0
  119. data/src/osx/bitmap.mm +133 -110
  120. data/src/osx/camera.mm +451 -0
  121. data/src/osx/font.mm +49 -62
  122. data/src/osx/helper.h +2 -2
  123. data/src/osx/opengl.mm +19 -83
  124. data/src/osx/rays.mm +3 -0
  125. data/src/painter.cpp +845 -671
  126. data/src/painter.h +24 -0
  127. data/src/point.cpp +140 -119
  128. data/src/polygon.cpp +1266 -0
  129. data/src/polygon.h +32 -0
  130. data/src/polyline.cpp +160 -0
  131. data/src/polyline.h +69 -0
  132. data/src/render_buffer.cpp +11 -4
  133. data/src/render_buffer.h +2 -2
  134. data/src/shader.cpp +163 -106
  135. data/src/shader.h +38 -0
  136. data/src/shader_program.cpp +533 -0
  137. data/src/{program.h → shader_program.h} +28 -16
  138. data/src/shader_source.cpp +140 -0
  139. data/src/shader_source.h +52 -0
  140. data/src/texture.cpp +136 -160
  141. data/src/texture.h +65 -0
  142. data/src/win32/bitmap.cpp +62 -52
  143. data/src/win32/font.cpp +11 -13
  144. data/src/win32/font.h +24 -0
  145. data/src/win32/gdi.h +6 -6
  146. data/test/helper.rb +0 -3
  147. data/test/test_bitmap.rb +31 -7
  148. data/test/test_bounds.rb +36 -0
  149. data/test/test_color.rb +59 -19
  150. data/test/test_color_space.rb +95 -0
  151. data/test/test_font.rb +5 -0
  152. data/test/test_image.rb +24 -20
  153. data/test/test_matrix.rb +106 -0
  154. data/test/test_painter.rb +157 -51
  155. data/test/test_painter_shape.rb +102 -0
  156. data/test/test_point.rb +29 -0
  157. data/test/test_polygon.rb +234 -0
  158. data/test/test_polygon_line.rb +167 -0
  159. data/test/test_polyline.rb +171 -0
  160. data/test/test_shader.rb +9 -9
  161. metadata +102 -70
  162. data/.doc/ext/rays/texture.cpp +0 -138
  163. data/ext/rays/texture.cpp +0 -149
  164. data/include/rays/ruby/texture.h +0 -41
  165. data/include/rays/texture.h +0 -71
  166. data/lib/rays/texture.rb +0 -24
  167. data/src/program.cpp +0 -648
  168. data/test/test_texture.rb +0 -27
@@ -0,0 +1,25 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_SRC_IMAGE_H__
4
+ #define __RAYS_SRC_IMAGE_H__
5
+
6
+
7
+ #include <rays/image.h>
8
+
9
+
10
+ namespace Rays
11
+ {
12
+
13
+
14
+ class Texture;
15
+
16
+
17
+ Texture& Image_get_texture ( Image& image);
18
+
19
+ const Texture& Image_get_texture (const Image& image);
20
+
21
+
22
+ }// Rays
23
+
24
+
25
+ #endif//EOH
@@ -0,0 +1,23 @@
1
+ // -*- mode: c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_SRC_IOS_BITMAP_H__
4
+ #define __RAYS_SRC_IOS_BITMAP_H__
5
+
6
+
7
+ #import <CoreGraphics/CGImage.h>
8
+ #include "../bitmap.h"
9
+
10
+
11
+ namespace Rays
12
+ {
13
+
14
+
15
+ void Bitmap_draw_image (
16
+ Bitmap* bitmap, CGImageRef image,
17
+ coord x = 0, coord y = 0, coord width = -1, coord height = -1);
18
+
19
+
20
+ }// Rays
21
+
22
+
23
+ #endif//EOH
@@ -1,13 +1,13 @@
1
1
  // -*- objc -*-
2
- #import "rays/bitmap.h"
2
+ #import "bitmap.h"
3
3
 
4
4
 
5
- #include <assert.h>
6
- #include <boost/scoped_array.hpp>
7
- #import <ImageIO/ImageIO.h>
5
+ #import <ImageIO/CGImageDestination.h>
8
6
  #import <MobileCoreServices/UTCoreTypes.h>
9
7
  #include "rays/exception.h"
10
- #include "rays/texture.h"
8
+ #include "../color_space.h"
9
+ #include "../font.h"
10
+ #include "../texture.h"
11
11
  #include "../frame_buffer.h"
12
12
  #include "helper.h"
13
13
 
@@ -27,14 +27,14 @@ namespace Rays
27
27
  if (cs.is_alpha_first())
28
28
  {
29
29
  info |= cs.is_premult()
30
- ? kCGImageAlphaPremultipliedFirst
31
- : kCGImageAlphaFirst;
30
+ ? kCGImageAlphaPremultipliedFirst
31
+ : kCGImageAlphaFirst;
32
32
  }
33
33
  else if (cs.is_alpha_last())
34
34
  {
35
35
  info |= cs.is_premult()
36
- ? kCGImageAlphaPremultipliedLast
37
- : kCGImageAlphaLast;
36
+ ? kCGImageAlphaPremultipliedLast
37
+ : kCGImageAlphaLast;
38
38
  }
39
39
  else if (cs.is_skip_first())
40
40
  info |= kCGImageAlphaNoneSkipFirst;
@@ -60,14 +60,13 @@ namespace Rays
60
60
 
61
61
  ColorSpace color_space;
62
62
 
63
- void* pixels;
63
+ void* pixels = NULL;
64
64
 
65
- CGContextRef context;
65
+ CGContextRef context = NULL;
66
66
 
67
- bool dirty;
67
+ bool modified;
68
68
 
69
69
  Data ()
70
- : pixels(NULL), context(NULL)
71
70
  {
72
71
  clear();
73
72
  }
@@ -86,7 +85,7 @@ namespace Rays
86
85
  if (bpc <= 0 || pitch <= 0) return NULL;
87
86
 
88
87
  CGColorSpaceRef cgcs = NULL;
89
- if (color_space.is_gray())
88
+ if (color_space.is_gray() || color_space.is_alpha())
90
89
  cgcs = CGColorSpaceCreateDeviceGray();
91
90
  else if (color_space.is_rgb() || color_space.is_bgr())
92
91
  cgcs = CGColorSpaceCreateDeviceRGB();
@@ -115,7 +114,7 @@ namespace Rays
115
114
  color_space = COLORSPACE_UNKNOWN;
116
115
  pixels = NULL;
117
116
  context = NULL;
118
- dirty = false;
117
+ modified = false;
119
118
  }
120
119
 
121
120
  };// Bitmap::Data
@@ -135,7 +134,7 @@ namespace Rays
135
134
  this_->self->width = w;
136
135
  this_->self->height = h;
137
136
  this_->self->color_space = cs;
138
- this_->self->dirty = true;
137
+ this_->self->modified = true;
139
138
 
140
139
  size_t size = w * h * cs.Bpp();
141
140
  this_->self->pixels = new uchar[size];
@@ -152,16 +151,126 @@ namespace Rays
152
151
  if (!this_ || !tex)
153
152
  argument_error(__FILE__, __LINE__);
154
153
 
155
- setup_bitmap(this_, tex.width(), tex.height(), tex.color_space(), NULL, false);
154
+ setup_bitmap(
155
+ this_, tex.width(), tex.height(), tex.color_space(), NULL, false);
156
156
 
157
157
  GLenum format, type;
158
- tex.color_space().get_gl_enums(&format, &type, tex.alpha_only());
158
+ ColorSpace_get_gl_format_and_type(&format, &type, tex.color_space());
159
159
 
160
160
  FrameBuffer fb(tex);
161
161
  FrameBufferBinder binder(fb.id());
162
162
 
163
163
  for (int y = 0; y < this_->height(); ++y)
164
- glReadPixels(0, y, this_->width(), 1, format, type, (GLvoid*) this_->at<uchar>(0, y));
164
+ {
165
+ GLvoid* ptr = (GLvoid*) this_->at<uchar>(0, y);
166
+ glReadPixels(0, y, this_->width(), 1, format, type, ptr);
167
+ }
168
+ }
169
+
170
+ Bitmap
171
+ Bitmap_from (const Texture& texture)
172
+ {
173
+ Bitmap bmp;
174
+ setup_bitmap(&bmp, texture);
175
+ return bmp;
176
+ }
177
+
178
+ void
179
+ Bitmap_draw_image (
180
+ Bitmap* bitmap, CGImageRef image,
181
+ coord x, coord y, coord width, coord height)
182
+ {
183
+ if (width == 0 || height == 0) return;
184
+
185
+ if (!bitmap || !image)
186
+ argument_error(__FILE__, __LINE__);
187
+
188
+ CGContextRef context = bitmap->self->get_context();
189
+ if (!context)
190
+ rays_error(__FILE__, __LINE__, "getting CGContext failed.");
191
+
192
+ if (width < 0) width = (coord) CGImageGetWidth(image);
193
+ if (height < 0) height = (coord) CGImageGetHeight(image);
194
+ CGContextDrawImage(context, CGRectMake(x, y, width, height), image);
195
+
196
+ Bitmap_set_modified(bitmap);
197
+ }
198
+
199
+ void
200
+ Bitmap_draw_string (
201
+ Bitmap* bitmap, const RawFont& font, const char* str, coord x, coord y)
202
+ {
203
+ if (!bitmap || !*bitmap || !font || !str)
204
+ argument_error(__FILE__, __LINE__);
205
+
206
+ if (*str == '\0') return;
207
+
208
+ font.draw_string(bitmap->self->get_context(), bitmap->height(), str, x, y);
209
+
210
+ Bitmap_set_modified(bitmap);
211
+ }
212
+
213
+ void
214
+ Bitmap_set_modified (Bitmap* bitmap, bool modified)
215
+ {
216
+ assert(bitmap);
217
+
218
+ bitmap->self->modified = modified;
219
+ }
220
+
221
+ bool
222
+ Bitmap_get_modified (const Bitmap& bitmap)
223
+ {
224
+ return bitmap.self->modified;
225
+ }
226
+
227
+ void
228
+ Bitmap_save (const Bitmap& bmp, const char* path_)
229
+ {
230
+ std::shared_ptr<CGImage> img(bmp.self->get_image(), CGImageRelease);
231
+ if (!img)
232
+ rays_error(__FILE__, __LINE__, "getting CGImage failed.");
233
+
234
+ NSString* path = [NSString stringWithUTF8String: path_];
235
+ NSURL* url = [NSURL fileURLWithPath: path];
236
+ if (!url)
237
+ rays_error(__FILE__, __LINE__, "creating NSURL failed.");
238
+
239
+ std::shared_ptr<CGImageDestination> dest(
240
+ CGImageDestinationCreateWithURL((CFURLRef) url, kUTTypePNG, 1, NULL),
241
+ safe_cfrelease);
242
+ if (!dest)
243
+ rays_error(__FILE__, __LINE__, "CGImageDestinationCreateWithURL() failed.");
244
+
245
+ CGImageDestinationAddImage(dest.get(), img.get(), NULL);
246
+ if (!CGImageDestinationFinalize(dest.get()))
247
+ rays_error(__FILE__, __LINE__, "CGImageDestinationFinalize() failed.");
248
+ }
249
+
250
+ Bitmap
251
+ Bitmap_load (const char* path_)
252
+ {
253
+ if (!path_ || path_[0] == '\0')
254
+ argument_error(__FILE__, __LINE__);
255
+
256
+ NSString* path = [NSString stringWithUTF8String: path_];
257
+ UIImage* uiimage = [UIImage imageWithContentsOfFile: path];
258
+ if (!uiimage)
259
+ rays_error(__FILE__, __LINE__, "[UIImage imageWithContentsOfFile:] failed.");
260
+
261
+ CGImageRef image = [uiimage CGImage];
262
+ if (!image)
263
+ rays_error(__FILE__, __LINE__, "[imagerep CGImage] failed.");
264
+
265
+ size_t width = CGImageGetWidth(image);
266
+ size_t height = CGImageGetHeight(image);
267
+
268
+ Bitmap bmp((int) width, (int) height, RGBA);
269
+ if (!bmp)
270
+ rays_error(__FILE__, __LINE__, "invalid bitmap.");
271
+
272
+ Bitmap_draw_image(&bmp, image);
273
+ return bmp;
165
274
  }
166
275
 
167
276
 
@@ -175,17 +284,12 @@ namespace Rays
175
284
  setup_bitmap(this, width, height, color_space, pixels);
176
285
  }
177
286
 
178
- Bitmap::Bitmap (const Texture& texture)
179
- {
180
- setup_bitmap(this, texture);
181
- }
182
-
183
287
  Bitmap::~Bitmap ()
184
288
  {
185
289
  }
186
290
 
187
291
  Bitmap
188
- Bitmap::copy () const
292
+ Bitmap::dup () const
189
293
  {
190
294
  return Bitmap(width(), height(), color_space(), pixels());
191
295
  }
@@ -240,22 +344,13 @@ namespace Rays
240
344
  return const_cast<This*>(this)->pixels();
241
345
  }
242
346
 
243
- bool
244
- Bitmap::dirty () const
245
- {
246
- return self->dirty;
247
- }
248
-
249
- void
250
- Bitmap::set_dirty (bool b)
251
- {
252
- self->dirty = b;
253
- }
254
-
255
347
  Bitmap::operator bool () const
256
348
  {
257
349
  return
258
- self->width > 0 && self->height > 0 && self->color_space && self->pixels;
350
+ self->width > 0 &&
351
+ self->height > 0 &&
352
+ self->color_space &&
353
+ self->pixels;
259
354
  }
260
355
 
261
356
  bool
@@ -265,76 +360,4 @@ namespace Rays
265
360
  }
266
361
 
267
362
 
268
- Bitmap
269
- load_bitmap (const char* path_)
270
- {
271
- if (!path_ || path_[0] == '\0')
272
- argument_error(__FILE__, __LINE__);
273
-
274
- NSString* path = [NSString stringWithUTF8String: path_];
275
- UIImage* uiimage = [UIImage imageWithContentsOfFile: path];
276
- if (!uiimage)
277
- rays_error(__FILE__, __LINE__, "[UIImage imageWithContentsOfFile:] failed.");
278
-
279
- CGImageRef image = [uiimage CGImage];
280
- if (!image)
281
- rays_error(__FILE__, __LINE__, "[imagerep CGImage] failed.");
282
-
283
- size_t width = CGImageGetWidth(image);
284
- size_t height = CGImageGetHeight(image);
285
-
286
- Bitmap bmp((int) width, (int) height, RGBA);
287
- if (!bmp)
288
- rays_error(__FILE__, __LINE__, "invalid bitmap.");
289
-
290
- CGContextRef context = bmp.self->get_context();
291
- if (!context)
292
- rays_error(__FILE__, __LINE__, "creating CGContext failed.");
293
-
294
- CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
295
- return bmp;
296
- }
297
-
298
- void
299
- save_bitmap (const Bitmap& bmp, const char* path_)
300
- {
301
- boost::shared_ptr<CGImage> img(
302
- bmp.self->get_image(), CGImageRelease);
303
- if (!img)
304
- rays_error(__FILE__, __LINE__, "getting CGImage failed.");
305
-
306
- NSString* path = [NSString stringWithUTF8String: path_];
307
- NSURL* url = [NSURL fileURLWithPath: path];
308
- if (!url)
309
- rays_error(__FILE__, __LINE__, "creating NSURL failed.");
310
-
311
- boost::shared_ptr<CGImageDestination> dest(
312
- CGImageDestinationCreateWithURL((CFURLRef) url, kUTTypePNG, 1, NULL),
313
- safe_cfrelease);
314
- if (!dest)
315
- rays_error(__FILE__, __LINE__, "CGImageDestinationCreateWithURL() failed.");
316
-
317
- CGImageDestinationAddImage(dest.get(), img.get(), NULL);
318
- if (!CGImageDestinationFinalize(dest.get()))
319
- rays_error(__FILE__, __LINE__, "CGImageDestinationFinalize() failed.");
320
- }
321
-
322
-
323
- void draw_string (
324
- CGContextRef, coord, const char*, coord, coord, const Font&);
325
-
326
- void
327
- draw_string (
328
- Bitmap* bmp, const char* str, coord x, coord y, const Font& font)
329
- {
330
- if (!bmp || !*bmp || !str || !font)
331
- argument_error(__FILE__, __LINE__);
332
-
333
- if (*str == '\0') return;
334
-
335
- draw_string(bmp->self->get_context(), bmp->height(), str, x, y, font);
336
- bmp->set_dirty();
337
- }
338
-
339
-
340
363
  }// Rays
@@ -0,0 +1,510 @@
1
+ // -*- mode: objc -*-
2
+ #import "rays/camera.h"
3
+
4
+
5
+ #import <AVFoundation/AVFoundation.h>
6
+ #include "rays/exception.h"
7
+ #include "bitmap.h"
8
+
9
+
10
+ static int video_input_queue_index = 0;
11
+
12
+
13
+ @interface VideoInput : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
14
+ @end
15
+
16
+
17
+ @implementation VideoInput
18
+
19
+ {
20
+ AVCaptureSession* session;
21
+ dispatch_queue_t queue;
22
+ CGImageRef image;
23
+ AVCaptureVideoOrientation orientation;
24
+ }
25
+
26
+ - (id) init
27
+ {
28
+ self = [super init];
29
+ if (self)
30
+ {
31
+ session = nil;
32
+ queue = nil;
33
+ image = nil;
34
+ orientation = AVCaptureVideoOrientationPortrait;
35
+ }
36
+ return self;
37
+ }
38
+
39
+ - (void) dealloc
40
+ {
41
+ [self stop];
42
+ [self clearImage];
43
+
44
+ if (queue)
45
+ {
46
+ dispatch_release(queue);
47
+ queue = nil;
48
+ }
49
+
50
+ [super dealloc];
51
+ }
52
+
53
+ - (dispatch_queue_t) getQueue
54
+ {
55
+ if (!queue)
56
+ {
57
+ auto name = Xot::stringf(
58
+ "org.xord.RaysVideoInputQueue_%d",
59
+ video_input_queue_index++);
60
+ queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
61
+ }
62
+ return queue;
63
+ }
64
+
65
+ - (BOOL) start: (AVCaptureDevice*) device
66
+ preset: (AVCaptureSessionPreset) preset
67
+ {
68
+ if (!device) return NO;
69
+
70
+ [self stop];
71
+ [self updateOrientation];
72
+
73
+ AVCaptureSession* sess = [[[AVCaptureSession alloc] init] autorelease];
74
+ if (preset != nil)
75
+ sess.sessionPreset = preset;
76
+
77
+ //device.activeVideoMinFrameDuration = CMTimeMake(1, 30);
78
+
79
+ NSError* error = nil;
80
+ AVCaptureDeviceInput* input = [[[AVCaptureDeviceInput alloc]
81
+ initWithDevice: device error: &error]
82
+ autorelease];
83
+ if (!input || error || ![sess canAddInput: input])
84
+ return NO;
85
+
86
+ AVCaptureVideoDataOutput* output =
87
+ [[[AVCaptureVideoDataOutput alloc] init] autorelease];
88
+ output.videoSettings = @{
89
+ (NSString*) kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)
90
+ };
91
+ output.alwaysDiscardsLateVideoFrames = YES;
92
+ [output setSampleBufferDelegate: self queue: [self getQueue]];
93
+ if (![sess canAddOutput: output])
94
+ return NO;
95
+
96
+ [sess addInput: input];
97
+ [sess addOutput: output];
98
+
99
+ AVCaptureConnection* connection =
100
+ [output connectionWithMediaType: AVMediaTypeVideo];
101
+ if (connection)
102
+ {
103
+ if (connection.isVideoOrientationSupported)
104
+ [connection setVideoOrientation: orientation];
105
+
106
+ if (connection.isVideoMirroringSupported)
107
+ {
108
+ [connection setVideoMirrored:
109
+ device.position == AVCaptureDevicePositionFront];
110
+ }
111
+ }
112
+
113
+ [sess startRunning];
114
+
115
+ session = [sess retain];
116
+ return YES;
117
+ }
118
+
119
+ - (void) updateCaptureOrientation
120
+ {
121
+ assert(Thread.isMainThread);
122
+
123
+ switch (UIApplication.sharedApplication.statusBarOrientation)
124
+ {
125
+ case UIInterfaceOrientationPortraitUpsideDown:
126
+ orientation = AVCaptureVideoOrientationPortraitUpsideDown;
127
+ break;
128
+
129
+ case UIInterfaceOrientationPortraitLandscapeLeft:
130
+ orientation = AVCaptureVideoOrientationLandscapeLeft;
131
+ break;
132
+
133
+ case UIInterfaceOrientationPortraitLandscapeRight:
134
+ orientation = AVCaptureVideoOrientationLandscapeRight;
135
+ break;
136
+
137
+ default:
138
+ orientation = AVCaptureVideoOrientationPortrait;
139
+ break;
140
+ }
141
+ }
142
+
143
+ - (void) captureOutput: (AVCaptureOutput*) output
144
+ didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer
145
+ fromConnection: (AVCaptureConnection*) connection
146
+ {
147
+ [connection setVideoOrientation: orientation];
148
+
149
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
150
+ if (!pixelBuffer) return;
151
+
152
+ CIImage* ciImage = [CIImage imageWithCVPixelBuffer: pixelBuffer];
153
+ if (!ciImage) return;
154
+
155
+ CIContext* context = [CIContext contextWithOptions: nil];
156
+ size_t width = CVPixelBufferGetWidth(pixelBuffer);
157
+ size_t height = CVPixelBufferGetHeight(pixelBuffer);
158
+ CGRect rect = CGRectMake(0, 0, width, height);
159
+ CGImageRef cgImage = [context createCGImage: ciImage fromRect: rect];
160
+
161
+ dispatch_async(dispatch_get_main_queue(), ^{
162
+ [self clearImage];
163
+ image = cgImage;
164
+
165
+ [self updateOrientation];
166
+ });
167
+ }
168
+
169
+ - (void) stop
170
+ {
171
+ if (!session) return;
172
+
173
+ [session stopRunning];
174
+ [session release];
175
+ session = nil;
176
+ }
177
+
178
+ - (BOOL) isActive
179
+ {
180
+ return session != nil;
181
+ }
182
+
183
+ - (void) clearImage
184
+ {
185
+ if (!image) return;
186
+
187
+ CGImageRelease(image);
188
+ image = nil;
189
+ }
190
+
191
+ - (CGImageRef) getImage
192
+ {
193
+ return image;
194
+ }
195
+
196
+ @end// VideoInput
197
+
198
+
199
+ namespace Rays
200
+ {
201
+
202
+
203
+ struct Camera::Data
204
+ {
205
+
206
+ String device_name;
207
+
208
+ int min_width = -1, min_height = -1;
209
+
210
+ bool resize = false, crop = false;
211
+
212
+ mutable Image image;
213
+
214
+ VideoInput* video_input = nil;
215
+
216
+ AVCaptureSessionPreset get_preset (AVCaptureDevice* device)
217
+ {
218
+ int w = min_width, h = min_height;
219
+ if (w > 0 && h > 0)
220
+ {
221
+ #define SUPPORT(x) \
222
+ [device supportsAVCaptureSessionPreset: AVCaptureSessionPreset##x]
223
+
224
+ //if (w <= 320 && h <= 240 && SUPPORT(320x240))
225
+ // return AVCaptureSessionPreset320x240;
226
+
227
+ if (w <= 352 && h <= 288 && SUPPORT(352x288))
228
+ return AVCaptureSessionPreset352x288;
229
+
230
+ if (w <= 640 && h <= 480 && SUPPORT(640x480))
231
+ return AVCaptureSessionPreset640x480;
232
+
233
+ //if (w <= 960 && h <= 540 && SUPPORT(960x540))
234
+ // return AVCaptureSessionPreset960x540;
235
+
236
+ if (w <= 1280 && h <= 720 && SUPPORT(1280x720))
237
+ return AVCaptureSessionPreset1280x720;
238
+
239
+ if (/*w <= 1920 && h <= 1080 &&*/ SUPPORT(1920x1080))
240
+ return AVCaptureSessionPreset1920x1080;
241
+
242
+ //if (SUPPORT(3840x2160))
243
+ // return AVCaptureSessionPreset3840x2160;
244
+
245
+ #undef SUPPORT
246
+ }
247
+
248
+ return nil;
249
+ }
250
+
251
+ void update_image_from_video_input () const
252
+ {
253
+ if (!video_input) return;
254
+
255
+ CGImageRef cgImage = [video_input getImage];
256
+ if (!cgImage) return;
257
+
258
+ coord draw_x, draw_y, draw_width, draw_height;
259
+ int bitmap_width, bitmap_height;
260
+ get_draw_bounds(
261
+ &draw_x, &draw_y, &draw_width, &draw_height,
262
+ &bitmap_width, &bitmap_height,
263
+ cgImage);
264
+
265
+ if (
266
+ !image ||
267
+ image.bitmap().width() != bitmap_width ||
268
+ image.bitmap().height() != bitmap_height)
269
+ {
270
+ image = Image(Bitmap(bitmap_width, bitmap_height));
271
+ }
272
+
273
+ Bitmap_draw_image(
274
+ &image.bitmap(), cgImage,
275
+ draw_x, draw_y, draw_width, draw_height);
276
+
277
+ [video_input clearImage];
278
+ }
279
+
280
+ void get_draw_bounds (
281
+ coord* draw_x, coord* draw_y, coord* draw_width, coord* draw_height,
282
+ int* bitmap_width, int* bitmap_height,
283
+ CGImageRef image) const
284
+ {
285
+ int image_width = (int) CGImageGetWidth(image);
286
+ int image_height = (int) CGImageGetHeight(image);
287
+ float image_ratio = (float) image_width / (float) image_height;
288
+
289
+ if (resize && min_width > 0 && min_height > 0)
290
+ {
291
+ float min_size_ratio = (float) min_width / (float) min_height;
292
+ if (image_ratio > min_size_ratio)
293
+ {
294
+ *draw_width = min_height * image_ratio;
295
+ *draw_height = min_height;
296
+ }
297
+ else
298
+ {
299
+ *draw_width = min_width;
300
+ *draw_height = min_width / image_ratio;
301
+ }
302
+ }
303
+ else if (resize && min_width > 0)
304
+ {
305
+ *draw_width = min_width;
306
+ *draw_height = min_width / image_ratio;
307
+ }
308
+ else if (resize && min_height > 0)
309
+ {
310
+ *draw_width = min_height * image_ratio;
311
+ *draw_height = min_height;
312
+ }
313
+ else
314
+ {
315
+ *draw_width = image_width;
316
+ *draw_height = image_height;
317
+ }
318
+
319
+ *draw_x = 0;
320
+ *draw_y = 0;
321
+ *bitmap_width = *draw_width;
322
+ *bitmap_height = *draw_height;
323
+
324
+ if (crop && min_width > 0)
325
+ {
326
+ *draw_x = min_width / 2 - *draw_width / 2;
327
+ *bitmap_width = min_width;
328
+ }
329
+ else if (crop && min_height > 0)
330
+ {
331
+ *draw_y = min_height / 2 - *draw_height / 2;
332
+ *bitmap_height = min_height;
333
+ }
334
+ }
335
+
336
+ };// Camera::Data
337
+
338
+
339
+ static NSArray<AVCaptureDevice*>*
340
+ get_video_devices ()
341
+ {
342
+ #if 0
343
+ AVCaptureDeviceDiscoverySession* discoverySession =
344
+ [AVCaptureDeviceDiscoverySession
345
+ discoverySessionWithDeviceTypes: @[
346
+ AVCaptureDeviceTypeBuiltInWideAngleCamera]
347
+ mediaType: AVMediaTypeVideo
348
+ position: AVCaptureDevicePositionUnspecified];
349
+ NSArray<AVCaptureDevice*>* devices = discoverySession.devices;
350
+ for (AVCaptureDevice* d in devices)
351
+ {
352
+ printf("%s\n", d.localizedName.UTF8String);
353
+ }
354
+ #endif
355
+ NSMutableArray<AVCaptureDevice*>* devices = [NSMutableArray array];
356
+ for (AVCaptureDevice* d in AVCaptureDevice.devices)
357
+ {
358
+ if ([d hasMediaType: AVMediaTypeVideo])
359
+ [devices addObject: d];
360
+ }
361
+ return devices;
362
+ }
363
+
364
+ static AVCaptureDevice*
365
+ get_default_video_device ()
366
+ {
367
+ AVCaptureDevice* device =
368
+ [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
369
+ if (!device)
370
+ rays_error(__FILE__, __LINE__, "Default camera device is not found.");
371
+
372
+ return device;
373
+ }
374
+
375
+ static AVCaptureDevice*
376
+ get_video_device (const char* name)
377
+ {
378
+ if (!name || *name == 0)
379
+ return get_default_video_device();
380
+
381
+ for (AVCaptureDevice* d in get_video_devices())
382
+ {
383
+ if (strcmp(name, d.localizedName.UTF8String) == 0)
384
+ return d;
385
+ }
386
+
387
+ rays_error(__FILE__, __LINE__, "Camera device '%s' is not found.", name);
388
+ return nil;
389
+ }
390
+
391
+ std::vector<String>
392
+ get_camera_device_names ()
393
+ {
394
+ std::vector<String> names;
395
+ for (AVCaptureDevice* d in get_video_devices())
396
+ names.emplace_back(d.localizedName.UTF8String);
397
+ return names;
398
+ }
399
+
400
+
401
+ Camera::Camera (
402
+ const char* device_name,
403
+ int min_width, int min_height, bool resize, bool crop)
404
+ {
405
+ if (device_name)
406
+ self->device_name = device_name;
407
+
408
+ self->min_width = min_width;
409
+ self->min_height = min_height;
410
+ self->resize = resize;
411
+ self->crop = crop;
412
+ }
413
+
414
+ Camera::~Camera ()
415
+ {
416
+ stop();
417
+ if (self->video_input) [self->video_input release];
418
+ }
419
+
420
+ bool
421
+ Camera::start ()
422
+ {
423
+ if (!self->video_input) self->video_input = [[VideoInput alloc] init];
424
+
425
+ AVCaptureDevice* device = get_video_device(self->device_name.c_str());
426
+ return [self->video_input start: device preset: self->get_preset(device)];
427
+ }
428
+
429
+ void
430
+ Camera::stop ()
431
+ {
432
+ if (!self->video_input) return;
433
+
434
+ [self->video_input stop];
435
+ }
436
+
437
+ bool
438
+ Camera::is_active () const
439
+ {
440
+ return self->video_input && [self->video_input isActive];
441
+ }
442
+
443
+ void
444
+ Camera::set_min_width (int width)
445
+ {
446
+ self->min_width = width;
447
+ }
448
+
449
+ int
450
+ Camera::min_width () const
451
+ {
452
+ return self->min_width;
453
+ }
454
+
455
+ void
456
+ Camera::set_min_height (int height)
457
+ {
458
+ self->min_height = height;
459
+ }
460
+
461
+ int
462
+ Camera::min_height () const
463
+ {
464
+ return self->min_height;
465
+ }
466
+
467
+ void
468
+ Camera::set_resize (bool resize)
469
+ {
470
+ self->resize = resize;
471
+ }
472
+
473
+ bool
474
+ Camera::is_resize () const
475
+ {
476
+ return self->resize;
477
+ }
478
+
479
+ void
480
+ Camera::set_crop (bool crop)
481
+ {
482
+ self->crop = crop;
483
+ }
484
+
485
+ bool
486
+ Camera::is_crop () const
487
+ {
488
+ return self->crop;
489
+ }
490
+
491
+ const Image*
492
+ Camera::image () const
493
+ {
494
+ self->update_image_from_video_input();
495
+ return self->image ? &self->image : NULL;
496
+ }
497
+
498
+ Camera::operator bool () const
499
+ {
500
+ return true;
501
+ }
502
+
503
+ bool
504
+ Camera::operator ! () const
505
+ {
506
+ return !operator bool();
507
+ }
508
+
509
+
510
+ }// Rays