texplay 0.3.1 → 0.3.3pre2
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.
- 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
|