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.
- checksums.yaml +5 -5
- data/.doc/ext/rays/bitmap.cpp +22 -76
- data/.doc/ext/rays/bounds.cpp +95 -125
- data/.doc/ext/rays/camera.cpp +171 -0
- data/.doc/ext/rays/color.cpp +223 -45
- data/.doc/ext/rays/color_space.cpp +146 -46
- data/.doc/ext/rays/defs.cpp +183 -0
- data/.doc/ext/rays/font.cpp +69 -21
- data/.doc/ext/rays/image.cpp +26 -37
- data/.doc/ext/rays/matrix.cpp +186 -29
- data/.doc/ext/rays/native.cpp +14 -8
- data/.doc/ext/rays/noise.cpp +53 -0
- data/.doc/ext/rays/painter.cpp +187 -292
- data/.doc/ext/rays/point.cpp +96 -77
- data/.doc/ext/rays/polygon.cpp +313 -0
- data/.doc/ext/rays/polygon_line.cpp +96 -0
- data/.doc/ext/rays/polyline.cpp +167 -0
- data/.doc/ext/rays/rays.cpp +103 -12
- data/.doc/ext/rays/shader.cpp +83 -9
- data/LICENSE +21 -0
- data/README.md +1 -1
- data/Rakefile +24 -9
- data/VERSION +1 -1
- data/ext/rays/bitmap.cpp +23 -81
- data/ext/rays/bounds.cpp +100 -128
- data/ext/rays/camera.cpp +186 -0
- data/ext/rays/color.cpp +231 -51
- data/ext/rays/color_space.cpp +149 -47
- data/ext/rays/defs.cpp +183 -0
- data/ext/rays/defs.h +26 -2
- data/ext/rays/extconf.rb +2 -3
- data/ext/rays/font.cpp +74 -24
- data/ext/rays/image.cpp +28 -40
- data/ext/rays/matrix.cpp +198 -30
- data/ext/rays/native.cpp +14 -8
- data/ext/rays/noise.cpp +55 -0
- data/ext/rays/painter.cpp +203 -298
- data/ext/rays/point.cpp +105 -81
- data/ext/rays/polygon.cpp +329 -0
- data/ext/rays/polygon_line.cpp +99 -0
- data/ext/rays/polyline.cpp +176 -0
- data/ext/rays/rays.cpp +103 -13
- data/ext/rays/shader.cpp +84 -9
- data/include/rays.h +10 -2
- data/include/rays/bitmap.h +14 -26
- data/include/rays/bounds.h +21 -4
- data/include/rays/camera.h +74 -0
- data/include/rays/color.h +25 -14
- data/include/rays/color_space.h +15 -10
- data/include/rays/coord.h +114 -0
- data/include/rays/debug.h +22 -0
- data/include/rays/defs.h +36 -0
- data/include/rays/exception.h +6 -2
- data/include/rays/font.h +4 -4
- data/include/rays/image.h +12 -18
- data/include/rays/matrix.h +50 -24
- data/include/rays/noise.h +42 -0
- data/include/rays/opengl.h +2 -50
- data/include/rays/painter.h +89 -93
- data/include/rays/point.h +44 -51
- data/include/rays/polygon.h +198 -0
- data/include/rays/polyline.h +71 -0
- data/include/rays/rays.h +3 -0
- data/include/rays/ruby.h +7 -1
- data/include/rays/ruby/bounds.h +1 -1
- data/include/rays/ruby/camera.h +41 -0
- data/include/rays/ruby/color.h +1 -1
- data/include/rays/ruby/color_space.h +1 -1
- data/include/rays/ruby/font.h +1 -1
- data/include/rays/ruby/matrix.h +1 -1
- data/include/rays/ruby/point.h +1 -1
- data/include/rays/ruby/polygon.h +52 -0
- data/include/rays/ruby/polyline.h +41 -0
- data/include/rays/ruby/rays.h +8 -0
- data/include/rays/ruby/shader.h +1 -1
- data/include/rays/shader.h +36 -8
- data/lib/rays.rb +7 -2
- data/lib/rays/bitmap.rb +0 -15
- data/lib/rays/bounds.rb +17 -23
- data/lib/rays/camera.rb +24 -0
- data/lib/rays/color.rb +20 -47
- data/lib/rays/color_space.rb +13 -13
- data/lib/rays/image.rb +3 -7
- data/lib/rays/matrix.rb +28 -0
- data/lib/rays/module.rb +4 -19
- data/lib/rays/painter.rb +78 -93
- data/lib/rays/point.rb +13 -21
- data/lib/rays/polygon.rb +58 -0
- data/lib/rays/polygon_line.rb +36 -0
- data/lib/rays/polyline.rb +32 -0
- data/lib/rays/shader.rb +20 -1
- data/rays.gemspec +5 -7
- data/src/bitmap.h +36 -0
- data/src/bounds.cpp +74 -11
- data/src/color.cpp +58 -23
- data/src/color_space.cpp +52 -34
- data/src/color_space.h +22 -0
- data/src/coord.cpp +170 -0
- data/src/coord.h +35 -0
- data/src/font.cpp +118 -0
- data/src/font.h +64 -0
- data/src/frame_buffer.cpp +37 -71
- data/src/frame_buffer.h +4 -4
- data/src/image.cpp +172 -98
- data/src/image.h +25 -0
- data/src/ios/bitmap.h +23 -0
- data/src/ios/bitmap.mm +133 -110
- data/src/ios/camera.mm +510 -0
- data/src/ios/font.mm +50 -62
- data/src/ios/helper.h +4 -4
- data/src/ios/opengl.mm +19 -4
- data/src/ios/rays.mm +3 -0
- data/src/matrix.cpp +111 -26
- data/src/matrix.h +30 -0
- data/src/noise.cpp +74 -0
- data/src/opengl.cpp +9 -27
- data/src/opengl.h +37 -0
- data/src/osx/bitmap.h +23 -0
- data/src/osx/bitmap.mm +133 -110
- data/src/osx/camera.mm +451 -0
- data/src/osx/font.mm +49 -62
- data/src/osx/helper.h +2 -2
- data/src/osx/opengl.mm +19 -83
- data/src/osx/rays.mm +3 -0
- data/src/painter.cpp +845 -671
- data/src/painter.h +24 -0
- data/src/point.cpp +140 -119
- data/src/polygon.cpp +1266 -0
- data/src/polygon.h +32 -0
- data/src/polyline.cpp +160 -0
- data/src/polyline.h +69 -0
- data/src/render_buffer.cpp +11 -4
- data/src/render_buffer.h +2 -2
- data/src/shader.cpp +163 -106
- data/src/shader.h +38 -0
- data/src/shader_program.cpp +533 -0
- data/src/{program.h → shader_program.h} +28 -16
- data/src/shader_source.cpp +140 -0
- data/src/shader_source.h +52 -0
- data/src/texture.cpp +136 -160
- data/src/texture.h +65 -0
- data/src/win32/bitmap.cpp +62 -52
- data/src/win32/font.cpp +11 -13
- data/src/win32/font.h +24 -0
- data/src/win32/gdi.h +6 -6
- data/test/helper.rb +0 -3
- data/test/test_bitmap.rb +31 -7
- data/test/test_bounds.rb +36 -0
- data/test/test_color.rb +59 -19
- data/test/test_color_space.rb +95 -0
- data/test/test_font.rb +5 -0
- data/test/test_image.rb +24 -20
- data/test/test_matrix.rb +106 -0
- data/test/test_painter.rb +157 -51
- data/test/test_painter_shape.rb +102 -0
- data/test/test_point.rb +29 -0
- data/test/test_polygon.rb +234 -0
- data/test/test_polygon_line.rb +167 -0
- data/test/test_polyline.rb +171 -0
- data/test/test_shader.rb +9 -9
- metadata +102 -70
- data/.doc/ext/rays/texture.cpp +0 -138
- data/ext/rays/texture.cpp +0 -149
- data/include/rays/ruby/texture.h +0 -41
- data/include/rays/texture.h +0 -71
- data/lib/rays/texture.rb +0 -24
- data/src/program.cpp +0 -648
- data/test/test_texture.rb +0 -27
data/src/image.h
ADDED
@@ -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
|
data/src/ios/bitmap.h
ADDED
@@ -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
|
data/src/ios/bitmap.mm
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
// -*- objc -*-
|
2
|
-
#import "
|
2
|
+
#import "bitmap.h"
|
3
3
|
|
4
4
|
|
5
|
-
#
|
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 "
|
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
|
-
?
|
31
|
-
:
|
30
|
+
? kCGImageAlphaPremultipliedFirst
|
31
|
+
: kCGImageAlphaFirst;
|
32
32
|
}
|
33
33
|
else if (cs.is_alpha_last())
|
34
34
|
{
|
35
35
|
info |= cs.is_premult()
|
36
|
-
?
|
37
|
-
:
|
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
|
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
|
-
|
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->
|
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(
|
154
|
+
setup_bitmap(
|
155
|
+
this_, tex.width(), tex.height(), tex.color_space(), NULL, false);
|
156
156
|
|
157
157
|
GLenum format, type;
|
158
|
-
|
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
|
-
|
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::
|
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
|
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
|
data/src/ios/camera.mm
ADDED
@@ -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
|