texplay 0.3.1 → 0.3.3pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/Rakefile +37 -13
- data/ext/texplay/graphics_utils.c +95 -26
- data/ext/texplay/texplay.h +62 -57
- data/lib/texplay-contrib.rb +111 -118
- data/lib/texplay.rb +36 -14
- data/lib/texplay/alone.rb +20 -0
- data/lib/texplay/c_function_docs.rb +3 -2
- data/lib/texplay/version.rb +1 -1
- data/live/live.rb +85 -0
- data/test/image_spec.rb +45 -0
- data/test/texplay_spec.rb +141 -0
- metadata +36 -13
- data/spec/image_spec.rb +0 -7
- data/spec/texplay_spec.rb +0 -80
data/.gemtest
ADDED
File without changes
|
data/Rakefile
CHANGED
@@ -1,17 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
direc = File.dirname(__FILE__)
|
2
|
+
dlext = Config::CONFIG['DLEXT']
|
3
|
+
project_name = "texplay"
|
3
4
|
|
4
5
|
require 'rake/clean'
|
5
6
|
require 'rake/gempackagetask'
|
7
|
+
require "#{direc}/lib/#{project_name}/version"
|
6
8
|
|
7
|
-
# get the texplay version
|
8
|
-
require './lib/texplay/version'
|
9
|
-
|
10
|
-
direc = File.dirname(__FILE__)
|
11
|
-
dlext = Config::CONFIG['DLEXT']
|
12
|
-
|
13
|
-
CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "ext/**/*.def", "ext/**/*.pdb")
|
14
9
|
CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o")
|
10
|
+
CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", "ext/**/*~",
|
11
|
+
"ext/**/*#*", "ext/**/*.obj", "ext/**/*.def", "ext/**/*.pdb")
|
15
12
|
|
16
13
|
def apply_spec_defaults(s)
|
17
14
|
s.name = "texplay"
|
@@ -23,13 +20,17 @@ def apply_spec_defaults(s)
|
|
23
20
|
s.description = s.summary
|
24
21
|
s.require_path = 'lib'
|
25
22
|
s.add_dependency("gosu",">=0.7.25")
|
23
|
+
s.add_development_dependency("bacon",">=1.1.0")
|
26
24
|
s.homepage = "http://banisterfiend.wordpress.com/2008/08/23/texplay-an-image-manipulation-tool-for-ruby-and-gosu/"
|
27
25
|
s.has_rdoc = 'yard'
|
28
|
-
s.files =
|
26
|
+
s.files = Dir["Rakefile", "README.markdown", "CHANGELOG",
|
29
27
|
"lib/**/*.rb", "ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c",
|
30
|
-
"examples/*.rb", "examples/media/*", "
|
28
|
+
"examples/*.rb", "examples/media/*", "test/*.rb", "live/*rb", ".gemtest"]
|
31
29
|
end
|
32
30
|
|
31
|
+
task :test do
|
32
|
+
sh "bacon -k #{direc}/test/texplay_spec.rb"
|
33
|
+
end
|
33
34
|
|
34
35
|
[:mingw32, :mswin32].each do |v|
|
35
36
|
namespace v do
|
@@ -50,7 +51,7 @@ namespace :ruby do
|
|
50
51
|
spec = Gem::Specification.new do |s|
|
51
52
|
apply_spec_defaults(s)
|
52
53
|
s.platform = Gem::Platform::RUBY
|
53
|
-
s.extensions = ["ext/
|
54
|
+
s.extensions = ["ext/#{project_name}/extconf.rb"]
|
54
55
|
end
|
55
56
|
|
56
57
|
Rake::GemPackageTask.new(spec) do |pkg|
|
@@ -58,9 +59,31 @@ namespace :ruby do
|
|
58
59
|
pkg.need_tar = false
|
59
60
|
end
|
60
61
|
end
|
62
|
+
|
63
|
+
directories = ["#{direc}/lib/1.8", "#{direc}/lib/1.9"]
|
64
|
+
directories.each { |d| directory d }
|
65
|
+
|
66
|
+
desc "build the 1.8 and 1.9 binaries from source and copy to lib/"
|
67
|
+
task :compile => directories do
|
68
|
+
build_for = proc do |pik_ver, ver|
|
69
|
+
sh %{ \
|
70
|
+
c:\\devkit\\devkitvars.bat && \
|
71
|
+
pik #{pik_ver} && \
|
72
|
+
ruby extconf.rb && \
|
73
|
+
make clean && \
|
74
|
+
make && \
|
75
|
+
cp *.so #{direc}/lib/#{ver} \
|
76
|
+
}
|
77
|
+
end
|
61
78
|
|
79
|
+
chdir("#{direc}/ext/#{project_name}") do
|
80
|
+
build_for.call("187", "1.8")
|
81
|
+
build_for.call("192", "1.9")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
62
85
|
desc "build all platform gems at once"
|
63
|
-
task :gems => ["mingw32:gem", "mswin32:gem", "ruby:gem"]
|
86
|
+
task :gems => [:clean, :rmgems, "mingw32:gem", "mswin32:gem", "ruby:gem"]
|
64
87
|
|
65
88
|
desc "remove all platform gems"
|
66
89
|
task :rmgems => ["ruby:clobber_package"]
|
@@ -73,3 +96,4 @@ task :pushgems => :gems do
|
|
73
96
|
end
|
74
97
|
end
|
75
98
|
end
|
99
|
+
|
@@ -14,6 +14,7 @@
|
|
14
14
|
static void initialize_action_struct(action_struct * cur, VALUE hash_arg, sync sync_mode);
|
15
15
|
static void process_common_hash_args(action_struct * cur, VALUE * hash_arg, sync sync_mode, bool primary);
|
16
16
|
static void prepare_drawing_mode(action_struct * cur);
|
17
|
+
static void prepare_alpha_blend(action_struct * cur);
|
17
18
|
static void prepare_fill_texture(action_struct * cur);
|
18
19
|
static void prepare_color_control(action_struct * cur);
|
19
20
|
static void prepare_color_select(action_struct * cur);
|
@@ -343,6 +344,8 @@ initialize_action_struct(action_struct * cur, VALUE hash_arg, sync sync_mode)
|
|
343
344
|
cur->pen.has_color_control_proc = false;
|
344
345
|
cur->pen.has_color_control_transform = false;
|
345
346
|
cur->pen.has_source_texture = false;
|
347
|
+
|
348
|
+
/* alpha blending */
|
346
349
|
cur->pen.alpha_blend = false;
|
347
350
|
|
348
351
|
/* set static color control transformations to defaults */
|
@@ -471,8 +474,48 @@ process_common_hash_args(action_struct * cur, VALUE * hash_arg, sync sync_mode,
|
|
471
474
|
prepare_fill_texture(cur);
|
472
475
|
|
473
476
|
/* does the user want to blend alpha values ? */
|
474
|
-
|
475
|
-
|
477
|
+
prepare_alpha_blend(cur);
|
478
|
+
}
|
479
|
+
|
480
|
+
static void
|
481
|
+
prepare_alpha_blend(action_struct * cur)
|
482
|
+
{
|
483
|
+
if(has_optional_hash_arg(cur->hash_arg, "alpha_blend")) {
|
484
|
+
|
485
|
+
VALUE blend_mode = get_from_hash(cur->hash_arg, "alpha_blend");
|
486
|
+
|
487
|
+
/* true is equivalent to default blend mode, 'source' */
|
488
|
+
if(blend_mode == Qtrue)
|
489
|
+
blend_mode = string2sym("source");
|
490
|
+
|
491
|
+
/* where false or nil is passed */
|
492
|
+
if(!RTEST(blend_mode)) {
|
493
|
+
cur->pen.alpha_blend = false;
|
494
|
+
return;
|
495
|
+
}
|
496
|
+
|
497
|
+
cur->pen.alpha_blend = true;
|
498
|
+
|
499
|
+
Check_Type(blend_mode, T_SYMBOL);
|
500
|
+
|
501
|
+
if(blend_mode == string2sym("source")) {
|
502
|
+
cur->pen.alpha_blend_mode = source;
|
503
|
+
}
|
504
|
+
else if(blend_mode == string2sym("dest")) {
|
505
|
+
cur->pen.alpha_blend_mode = dest;
|
506
|
+
}
|
507
|
+
else if(blend_mode == string2sym("source_with_fixed_alpha")) {
|
508
|
+
cur->pen.alpha_blend_mode = source_with_fixed_alpha;
|
509
|
+
}
|
510
|
+
else if(blend_mode == string2sym("dest_with_fixed_alpha")) {
|
511
|
+
cur->pen.alpha_blend_mode = dest_with_fixed_alpha;
|
512
|
+
}
|
513
|
+
else
|
514
|
+
rb_raise(rb_eArgError, "unrecognized blend mode: %s\n.",
|
515
|
+
sym2string(blend_mode));
|
516
|
+
|
517
|
+
}
|
518
|
+
|
476
519
|
|
477
520
|
}
|
478
521
|
|
@@ -591,10 +634,6 @@ prepare_color_control(action_struct * cur)
|
|
591
634
|
if(is_an_array(try_add)) {
|
592
635
|
|
593
636
|
cur->pen.color_add = convert_rb_color_to_rgba(try_add);
|
594
|
-
/* cur->pen.color_add.red = NUM2DBL(get_from_array(try_add, 0)); */
|
595
|
-
/* cur->pen.color_add.green = NUM2DBL(get_from_array(try_add, 1)); */
|
596
|
-
/* cur->pen.color_add.blue = NUM2DBL(get_from_array(try_add, 2)); */
|
597
|
-
/* cur->pen.color_add.alpha = NUM2DBL(get_from_array(try_add, 3)); */
|
598
637
|
|
599
638
|
cur->pen.has_color_control_transform = true;
|
600
639
|
}
|
@@ -602,11 +641,6 @@ prepare_color_control(action_struct * cur)
|
|
602
641
|
|
603
642
|
cur->pen.color_mult = convert_rb_color_to_rgba(try_mult);
|
604
643
|
|
605
|
-
/* cur->pen.color_mult.red = NUM2DBL(get_from_array(try_mult, 0)); */
|
606
|
-
/* cur->pen.color_mult.green = NUM2DBL(get_from_array(try_mult, 1)); */
|
607
|
-
/* cur->pen.color_mult.blue = NUM2DBL(get_from_array(try_mult, 2)); */
|
608
|
-
/* cur->pen.color_mult.alpha = NUM2DBL(get_from_array(try_mult, 3)); */
|
609
|
-
|
610
644
|
cur->pen.has_color_control_transform = true;
|
611
645
|
}
|
612
646
|
|
@@ -1068,33 +1102,68 @@ apply_color_control_transform(action_struct * payload, texture_info * tex, int x
|
|
1068
1102
|
static rgba
|
1069
1103
|
apply_alpha_blend(action_struct * payload, texture_info * tex, int x, int y, rgba blended_pixel)
|
1070
1104
|
{
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1105
|
+
rgba dest_pixel = get_pixel_color(tex, x, y);
|
1106
|
+
rgba finished_pixel;
|
1074
1107
|
|
1075
|
-
|
1076
|
-
|
1108
|
+
if (not_a_color(blended_pixel))
|
1109
|
+
return blended_pixel;
|
1110
|
+
|
1111
|
+
alpha_blend_mode_t blend_mode = payload->pen.alpha_blend_mode;
|
1077
1112
|
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1113
|
+
switch(blend_mode)
|
1114
|
+
{
|
1115
|
+
case source:
|
1116
|
+
case source_with_fixed_alpha:
|
1117
|
+
/** TO DO: rewrite this using sse2 instructions **/
|
1118
|
+
finished_pixel.red = blended_pixel.alpha * blended_pixel.red + (1 - blended_pixel.alpha)
|
1119
|
+
* dest_pixel.red;
|
1120
|
+
|
1121
|
+
finished_pixel.green = blended_pixel.alpha * blended_pixel.green + (1 - blended_pixel.alpha)
|
1122
|
+
* dest_pixel.green;
|
1123
|
+
|
1124
|
+
finished_pixel.blue = blended_pixel.alpha * blended_pixel.blue + (1 - blended_pixel.alpha)
|
1125
|
+
* dest_pixel.blue;
|
1126
|
+
|
1127
|
+
if(blend_mode == source) {
|
1128
|
+
finished_pixel.alpha = blended_pixel.alpha * blended_pixel.alpha + (1 - blended_pixel.alpha)
|
1129
|
+
* dest_pixel.alpha;
|
1130
|
+
}
|
1131
|
+
else {
|
1081
1132
|
|
1082
|
-
|
1083
|
-
|
1133
|
+
// fixed alpha
|
1134
|
+
finished_pixel.alpha = dest_pixel.alpha;
|
1135
|
+
}
|
1136
|
+
|
1137
|
+
break;
|
1138
|
+
case dest:
|
1139
|
+
case dest_with_fixed_alpha:
|
1140
|
+
finished_pixel.red = dest_pixel.alpha * blended_pixel.red + (1 - dest_pixel.alpha)
|
1084
1141
|
* dest_pixel.red;
|
1085
1142
|
|
1086
|
-
|
1143
|
+
finished_pixel.green = dest_pixel.alpha * blended_pixel.green + (1 - dest_pixel.alpha)
|
1087
1144
|
* dest_pixel.green;
|
1088
1145
|
|
1089
|
-
|
1146
|
+
finished_pixel.blue = dest_pixel.alpha * blended_pixel.blue + (1 - dest_pixel.alpha)
|
1090
1147
|
* dest_pixel.blue;
|
1091
1148
|
|
1149
|
+
if(blend_mode == dest) {
|
1150
|
+
finished_pixel.alpha = dest_pixel.alpha * blended_pixel.alpha + (1 - dest_pixel.alpha)
|
1151
|
+
* dest_pixel.alpha;
|
1152
|
+
}
|
1153
|
+
else {
|
1092
1154
|
|
1093
|
-
|
1094
|
-
|
1155
|
+
// fixed alpha
|
1156
|
+
finished_pixel.alpha = dest_pixel.alpha;
|
1157
|
+
}
|
1158
|
+
|
1159
|
+
break;
|
1160
|
+
default:
|
1161
|
+
rb_raise(rb_eRuntimeError,
|
1162
|
+
"apply_alpha_blend() impossible error. got %d\n", blend_mode);
|
1095
1163
|
|
1164
|
+
}
|
1096
1165
|
|
1097
|
-
|
1166
|
+
return finished_pixel;
|
1098
1167
|
}
|
1099
1168
|
|
1100
1169
|
/* NEW from utils.c */
|
data/ext/texplay/texplay.h
CHANGED
@@ -29,15 +29,15 @@
|
|
29
29
|
|
30
30
|
/* enums */
|
31
31
|
typedef enum e_bool {
|
32
|
-
|
32
|
+
false, true
|
33
33
|
} bool;
|
34
34
|
|
35
35
|
typedef enum e_color {
|
36
|
-
|
36
|
+
red, green, blue, alpha
|
37
37
|
} color_t;
|
38
38
|
|
39
39
|
typedef enum e_sync_mode {
|
40
|
-
|
40
|
+
lazy_sync, eager_sync, no_sync
|
41
41
|
} sync;
|
42
42
|
|
43
43
|
|
@@ -54,6 +54,10 @@ typedef enum {
|
|
54
54
|
difference, exclusion
|
55
55
|
} draw_mode;
|
56
56
|
|
57
|
+
typedef enum {
|
58
|
+
source, dest, source_with_fixed_alpha, dest_with_fixed_alpha
|
59
|
+
} alpha_blend_mode_t;
|
60
|
+
|
57
61
|
/* structs */
|
58
62
|
typedef struct s_rgba {
|
59
63
|
float red, green, blue, alpha;
|
@@ -67,80 +71,81 @@ typedef struct {
|
|
67
71
|
|
68
72
|
/* stores image data */
|
69
73
|
typedef struct {
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
int width, height;
|
75
|
+
float top, left;
|
76
|
+
int tname;
|
77
|
+
float * td_array;
|
78
|
+
int yincr, firstpixel;
|
79
|
+
int x_offset, y_offset;
|
80
|
+
VALUE image;
|
77
81
|
} texture_info;
|
78
82
|
|
79
83
|
|
80
84
|
/* convenience macro */
|
81
85
|
#define IMAGE_BOUNDS(X) ((image_bounds *) (X))
|
82
86
|
typedef struct {
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
+
int xmin;
|
88
|
+
int ymin;
|
89
|
+
int xmax;
|
90
|
+
int ymax;
|
87
91
|
} image_bounds;
|
88
92
|
|
89
93
|
|
90
94
|
typedef struct action_struct {
|
91
|
-
|
92
|
-
|
95
|
+
int xmin, ymin, xmax, ymax;
|
96
|
+
sync sync_mode;
|
93
97
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
+
/* pointer to associated texture */
|
99
|
+
/* a bit of a kludge having this here
|
100
|
+
since it's only being used by convert_image_local_color_to_rgba */
|
101
|
+
texture_info * tex;
|
98
102
|
|
99
|
-
|
100
|
-
|
101
|
-
/* action color */
|
102
|
-
rgba color;
|
103
|
+
VALUE hash_arg;
|
103
104
|
|
104
|
-
|
105
|
-
|
105
|
+
/* action color */
|
106
|
+
rgba color;
|
106
107
|
|
107
|
-
|
108
|
-
|
109
|
-
VALUE color_control_proc;
|
110
|
-
int color_control_arity;
|
108
|
+
/* pen data */
|
109
|
+
struct {
|
111
110
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
111
|
+
/* color control, dynamic */
|
112
|
+
bool has_color_control_proc;
|
113
|
+
VALUE color_control_proc;
|
114
|
+
int color_control_arity;
|
116
115
|
|
117
|
-
|
118
|
-
|
119
|
-
|
116
|
+
/* color control, static */
|
117
|
+
bool has_color_control_transform;
|
118
|
+
rgba color_mult;
|
119
|
+
rgba color_add;
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
121
|
+
/* texture fill */
|
122
|
+
bool has_source_texture;
|
123
|
+
texture_info source_tex;
|
124
124
|
|
125
|
-
|
126
|
-
|
125
|
+
/* lerp */
|
126
|
+
bool has_lerp;
|
127
|
+
float lerp;
|
127
128
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
129
|
+
/* alpha blend */
|
130
|
+
bool alpha_blend;
|
131
|
+
alpha_blend_mode_t alpha_blend_mode;
|
132
|
+
|
133
|
+
/* drawing mode */
|
134
|
+
bool has_drawing_mode;
|
135
|
+
draw_mode drawing_mode;
|
136
|
+
|
137
|
+
/* tolerance */
|
138
|
+
bool has_tolerance;
|
139
|
+
float tolerance;
|
140
|
+
|
141
|
+
/* color selection */
|
142
|
+
bool has_color_select;
|
143
|
+
rgba_list source_select;
|
144
|
+
rgba_list source_ignore;
|
145
|
+
rgba_list dest_select;
|
146
|
+
rgba_list dest_ignore;
|
142
147
|
|
143
|
-
|
148
|
+
} pen;
|
144
149
|
|
145
150
|
} action_struct;
|
146
151
|
|
data/lib/texplay-contrib.rb
CHANGED
@@ -1,171 +1,164 @@
|
|
1
|
-
begin
|
2
|
-
require 'rubygems'
|
3
|
-
rescue LoadError
|
4
|
-
end
|
5
|
-
|
6
|
-
require 'texplay'
|
7
|
-
|
8
1
|
# to bring in String#each_char for 1.8
|
9
2
|
if RUBY_VERSION =~ /1.8/
|
10
|
-
|
3
|
+
require 'jcode'
|
11
4
|
end
|
12
5
|
|
13
6
|
# setup will be executed straight after Gosu::Image instantiation
|
14
7
|
TexPlay::on_setup do
|
15
|
-
|
16
|
-
|
8
|
+
@turtle_pos = TexPlay::TPPoint.new(width / 2, height / 2 )
|
9
|
+
@turtle_angle = 0
|
17
10
|
end
|
18
11
|
|
19
12
|
|
20
13
|
TexPlay::create_macro(:move_to) do |x, y|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
14
|
+
capture {
|
15
|
+
@turtle_pos.x = x
|
16
|
+
@turtle_pos.y = y
|
17
|
+
}
|
25
18
|
end
|
26
19
|
|
27
20
|
TexPlay::create_macro(:move_rel) do |dx, dy|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
21
|
+
capture {
|
22
|
+
@turtle_pos.x += dx
|
23
|
+
@turtle_pos.y += dy
|
24
|
+
}
|
32
25
|
end
|
33
26
|
|
34
27
|
TexPlay::create_macro(:line_to) do |x, y, *other|
|
35
|
-
|
36
|
-
|
28
|
+
capture {
|
29
|
+
line(@turtle_pos.x, @turtle_pos.y, x, y, *other)
|
37
30
|
|
38
|
-
|
39
|
-
|
31
|
+
@turtle_pos.x, @turtle_pos.y = x, y
|
32
|
+
}
|
40
33
|
end
|
41
34
|
|
42
35
|
TexPlay::create_macro(:line_rel) do |dx, dy, *other|
|
43
|
-
|
44
|
-
|
45
|
-
|
36
|
+
capture {
|
37
|
+
x = @turtle_pos.x + dx
|
38
|
+
y = @turtle_pos.y + dy
|
46
39
|
|
47
|
-
|
40
|
+
line(@turtle_pos.x, @turtle_pos.y, x, y, *other)
|
48
41
|
|
49
|
-
|
50
|
-
|
42
|
+
@turtle_pos.x, @turtle_pos.y = x, y
|
43
|
+
}
|
51
44
|
end
|
52
45
|
|
53
46
|
TexPlay::create_macro(:turn_to) do |a|
|
54
|
-
|
55
|
-
|
56
|
-
|
47
|
+
capture {
|
48
|
+
@turtle_angle = a
|
49
|
+
}
|
57
50
|
end
|
58
51
|
|
59
52
|
TexPlay::create_macro(:turn) do |da|
|
60
|
-
|
61
|
-
|
62
|
-
|
53
|
+
capture {
|
54
|
+
@turtle_angle += da
|
55
|
+
}
|
63
56
|
end
|
64
57
|
|
65
58
|
TexPlay::create_macro(:forward) do |dist, *other|
|
66
|
-
|
67
|
-
|
59
|
+
capture {
|
60
|
+
visible = other.shift
|
68
61
|
|
69
|
-
|
62
|
+
radians_per_degree = 0.0174532925199433
|
70
63
|
|
71
|
-
|
72
|
-
|
64
|
+
x = @turtle_pos.x + dist * Math::cos(radians_per_degree * @turtle_angle)
|
65
|
+
y = @turtle_pos.y + dist * Math::sin(radians_per_degree * @turtle_angle)
|
73
66
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
67
|
+
if(visible) then
|
68
|
+
line_to(x, y, *other)
|
69
|
+
else
|
70
|
+
move_to(x, y)
|
71
|
+
end
|
72
|
+
}
|
80
73
|
end
|
81
74
|
|
82
75
|
# L-System code
|
83
76
|
# adding LSystem class to TexPlay module
|
84
77
|
class TexPlay::LSystem
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
instance_eval(&block) if block
|
89
|
-
end
|
78
|
+
def initialize(&block)
|
79
|
+
@rules = {}
|
90
80
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
81
|
+
instance_eval(&block) if block
|
82
|
+
end
|
83
|
+
|
84
|
+
def rule(new_rule)
|
85
|
+
@rules.merge!(new_rule)
|
86
|
+
end
|
87
|
+
|
88
|
+
def atom(new_atom)
|
89
|
+
@atom = new_atom
|
90
|
+
end
|
91
|
+
|
92
|
+
def angle(new_angle=nil)
|
93
|
+
return @angle if !new_angle
|
94
|
+
@angle = new_angle
|
95
|
+
end
|
96
|
+
|
97
|
+
def produce_string(order)
|
98
|
+
order = order[:order]
|
99
|
+
string = @atom.dup
|
100
|
+
|
101
|
+
order.times do
|
102
|
+
i = 0
|
103
|
+
while(i < string.length)
|
104
|
+
sub = @rules[string[i, 1]]
|
107
105
|
|
108
|
-
|
109
|
-
i = 0
|
110
|
-
while(i < string.length)
|
111
|
-
sub = @rules[string[i, 1]]
|
112
|
-
|
113
|
-
string[i] = sub if sub
|
114
|
-
|
115
|
-
i += sub ? sub.length : 1
|
116
|
-
end
|
117
|
-
end
|
106
|
+
string[i] = sub if sub
|
118
107
|
|
119
|
-
|
108
|
+
i += sub ? sub.length : 1
|
109
|
+
end
|
120
110
|
end
|
111
|
+
|
112
|
+
string
|
113
|
+
end
|
121
114
|
end
|
122
115
|
|
123
116
|
# L-System macro
|
124
117
|
TexPlay::create_macro(:lsystem) do |x, y, system, options|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
118
|
+
capture {
|
119
|
+
theta = system.angle
|
120
|
+
turtle_stack = []
|
121
|
+
move_to(x, y)
|
122
|
+
line_length = options[:line_length] || 1
|
123
|
+
|
124
|
+
system.produce_string(options).each_char do |v|
|
125
|
+
|
126
|
+
case v
|
127
|
+
when "F"
|
128
|
+
forward(line_length, true)
|
129
|
+
when "+"
|
130
|
+
turn(theta)
|
131
|
+
when "-"
|
132
|
+
turn(-theta)
|
133
|
+
when "["
|
134
|
+
turtle_stack.push([@turtle_pos.dup, @turtle_angle])
|
135
|
+
when "]"
|
136
|
+
@turtle_pos, @turtle_angle = turtle_stack.pop
|
137
|
+
end
|
138
|
+
end
|
139
|
+
}
|
147
140
|
end
|
148
141
|
|
149
142
|
# Scaling
|
150
143
|
# uses nearest-neighbour
|
151
144
|
TexPlay::create_macro(:splice_and_scale) do |img, cx, cy, *options|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
145
|
+
options = options.first ? options.first : {}
|
146
|
+
|
147
|
+
options = {
|
148
|
+
:color_control => proc do |c1, c2, x, y|
|
149
|
+
factor = options[:factor] || 1
|
150
|
+
factor_x = options[:factor_x] || factor
|
151
|
+
factor_y = options[:factor_y] || factor
|
152
|
+
|
153
|
+
x = factor_x * (x - cx) + cx
|
154
|
+
y = factor_y * (y - cy) + cy
|
155
|
+
|
156
|
+
rect x, y, x + factor_x, y + factor_y, :color => c2, :fill => true
|
157
|
+
:none
|
158
|
+
end
|
159
|
+
}.merge!(options)
|
160
|
+
|
161
|
+
splice img, cx, cy, options
|
162
|
+
|
163
|
+
self
|
171
164
|
end
|