| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Model3D::WavefrontObject; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
27618
|
use 5.006; |
|
|
1
|
|
|
|
|
6
|
|
|
|
1
|
|
|
|
|
80
|
|
|
4
|
1
|
|
|
1
|
|
8
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
84
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our($VERSION); |
|
7
|
|
|
|
|
|
|
$VERSION = 1.00; |
|
8
|
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
42160
|
use Math::Trig; |
|
|
1
|
|
|
|
|
162789
|
|
|
|
1
|
|
|
|
|
23978
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub new { |
|
12
|
1
|
|
|
1
|
0
|
2323
|
my $p = shift; |
|
13
|
1
|
|
33
|
|
|
15
|
my $class = ref $p || $p; |
|
14
|
1
|
|
|
|
|
4
|
my $obj = {}; |
|
15
|
1
|
|
|
|
|
4
|
bless $obj, $class; |
|
16
|
1
|
|
|
|
|
25
|
$obj->_init(@_); |
|
17
|
1
|
|
|
|
|
11
|
return $obj; |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub _init { |
|
21
|
1
|
|
|
1
|
|
2
|
my $obj = shift; |
|
22
|
|
|
|
|
|
|
|
|
23
|
1
|
50
|
|
|
|
7
|
unless (scalar @_ % 2) { |
|
24
|
1
|
|
|
|
|
6
|
while (@_) { |
|
25
|
0
|
|
|
|
|
0
|
my $key = shift; |
|
26
|
0
|
|
|
|
|
0
|
$obj->{$key} = shift; |
|
27
|
|
|
|
|
|
|
} |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
|
|
30
|
1
|
|
50
|
|
|
18
|
$obj->{v} ||= []; |
|
31
|
1
|
|
50
|
|
|
9
|
$obj->{vt} ||= []; |
|
32
|
1
|
|
50
|
|
|
16
|
$obj->{vn} ||= []; |
|
33
|
1
|
|
50
|
|
|
7
|
$obj->{f} ||= []; |
|
34
|
1
|
|
50
|
|
|
12
|
$obj->{p} ||= []; |
|
35
|
1
|
|
50
|
|
|
27
|
$obj->{l} ||= []; |
|
36
|
1
|
|
50
|
|
|
8
|
$obj->{g} ||= {}; |
|
37
|
1
|
|
50
|
|
|
10
|
$obj->{group} ||= {}; |
|
38
|
1
|
|
50
|
|
|
7
|
$obj->{mtl} ||= {}; |
|
39
|
1
|
|
50
|
|
|
8
|
$obj->{comments} ||= []; |
|
40
|
1
|
|
50
|
|
|
6
|
$obj->{r} ||= {}; |
|
41
|
1
|
|
50
|
|
|
8
|
$obj->{_region} ||= 'none'; |
|
42
|
1
|
|
50
|
|
|
13
|
$obj->{_material} ||= 'default'; |
|
43
|
1
|
|
50
|
|
|
10
|
$obj->{_group} ||= 'NULL'; |
|
44
|
|
|
|
|
|
|
|
|
45
|
1
|
50
|
|
|
|
4
|
if ($obj->{objfile}) { |
|
46
|
0
|
|
|
|
|
0
|
$obj->ReadObj($obj->{objfile}); |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
|
|
49
|
1
|
|
|
|
|
2
|
return 1; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub ReadObj { |
|
53
|
1
|
|
|
1
|
1
|
703
|
my $obj = shift; |
|
54
|
1
|
|
|
|
|
4
|
$obj->{objfile} = shift; |
|
55
|
1
|
50
|
33
|
|
|
17
|
unless ($obj->{objfile} =~ /\.obj$/ and $obj->{objfile}) { |
|
56
|
0
|
|
|
|
|
0
|
$obj->{objfile} .= '.obj'; |
|
57
|
|
|
|
|
|
|
} |
|
58
|
1
|
50
|
|
|
|
681
|
unless (-e $obj->{objfile}) { |
|
59
|
1
|
|
|
|
|
5
|
return undef; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
0
|
0
|
|
|
|
0
|
if (-d $obj->{objfile}) { |
|
62
|
0
|
|
|
|
|
0
|
$obj->{errstr} = "$obj->{objfile} is a directory."; |
|
63
|
0
|
|
|
|
|
0
|
return undef; |
|
64
|
|
|
|
|
|
|
} |
|
65
|
0
|
0
|
|
|
|
0
|
unless (-s $obj->{objfile}) { |
|
66
|
0
|
|
|
|
|
0
|
$obj->{errstr} = "$obj->{objfile}: File is zero size."; |
|
67
|
0
|
0
|
|
|
|
0
|
unless (-w $obj->{objfile}) { |
|
68
|
0
|
|
|
|
|
0
|
$obj->{errstr} .= " Cannot modify file!"; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
0
|
|
|
|
|
0
|
return undef; |
|
71
|
|
|
|
|
|
|
} |
|
72
|
0
|
|
|
|
|
0
|
my $OBJ; |
|
73
|
0
|
0
|
|
|
|
0
|
unless (open ($OBJ, $obj->{objfile})) { |
|
74
|
0
|
|
|
|
|
0
|
$obj->{errstr} = "Can't read $obj->{objfile}: $!"; |
|
75
|
0
|
|
|
|
|
0
|
return undef; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
0
|
|
|
|
|
0
|
my $void = 1; |
|
78
|
0
|
|
|
|
|
0
|
my $vpid = 0; |
|
79
|
0
|
|
|
|
|
0
|
my $vtoid = 1; |
|
80
|
0
|
|
|
|
|
0
|
my $vnoid = 1; |
|
81
|
0
|
|
|
|
|
0
|
while (<$OBJ>) { |
|
82
|
0
|
|
|
|
|
0
|
chomp; |
|
83
|
0
|
|
|
|
|
0
|
s/\r//; |
|
84
|
0
|
|
|
|
|
0
|
s/^\s+//; |
|
85
|
0
|
|
|
|
|
0
|
s/\s+$//; |
|
86
|
0
|
0
|
|
|
|
0
|
if (/^v\s+/) { # Vertex line |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
0
|
/^v\s+([\d\+\-eE\.]+)\s+([\d\+\-eE\.]+)\s+([\d\+\-eE\.]+)\s*([\d\+\-eE\.]*)/; |
|
88
|
0
|
|
|
|
|
0
|
my $x = $1 + 0; |
|
89
|
0
|
|
|
|
|
0
|
my $y = $2 + 0; |
|
90
|
0
|
|
|
|
|
0
|
my $z = $3 + 0; |
|
91
|
0
|
|
0
|
|
|
0
|
my $wt = $4 + 0 || 1; |
|
92
|
0
|
|
|
|
|
0
|
push @{$obj->{v}}, {x => $x, |
|
|
0
|
|
|
|
|
0
|
|
|
93
|
|
|
|
|
|
|
y => $y, |
|
94
|
|
|
|
|
|
|
z => $z, |
|
95
|
|
|
|
|
|
|
wt => $wt, |
|
96
|
|
|
|
|
|
|
id => $void, |
|
97
|
|
|
|
|
|
|
pid => $vpid}; |
|
98
|
0
|
|
|
|
|
0
|
$void++; |
|
99
|
0
|
|
|
|
|
0
|
$vpid++; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
elsif (/^#\s*r\s+(.*)$/) { # UVMapper Region Extension |
|
102
|
0
|
|
|
|
|
0
|
push @{$obj->{r}}, $1; |
|
|
0
|
|
|
|
|
0
|
|
|
103
|
0
|
|
|
|
|
0
|
$obj->{r}->{$1} = 1; |
|
104
|
0
|
|
|
|
|
0
|
$obj->{_region} = $1; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
elsif (/^g$/) { # NULL group declaration |
|
107
|
0
|
|
|
|
|
0
|
my $group = 'NULL'; |
|
108
|
0
|
|
|
|
|
0
|
$obj->{g}->{NULL} = 1; |
|
109
|
0
|
|
|
|
|
0
|
$obj->{seengroup}->{$group} = 1; |
|
110
|
0
|
|
|
|
|
0
|
$obj->{_group} = $group; |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
elsif (/^g\s+(\S*)$/) { # named group declaration |
|
113
|
0
|
|
|
|
|
0
|
my $group = $1; |
|
114
|
0
|
0
|
|
|
|
0
|
$group = 'NULL' if lc $group eq '(null)'; |
|
115
|
0
|
|
|
|
|
0
|
$obj->{g}->{$group} = 1; |
|
116
|
0
|
|
|
|
|
0
|
$obj->{_group} = $group; |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
elsif (/^usemtl\s*(\S*)/) { # Material declaration |
|
119
|
0
|
|
|
|
|
0
|
my $material = $1; |
|
120
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$material} = ''; |
|
121
|
0
|
|
|
|
|
0
|
$obj->{_material} = $material; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
elsif (/^mtllib\s+(.*)\s*$/) { # declare material library |
|
124
|
0
|
|
|
|
|
0
|
my $mtllib = $1; |
|
125
|
0
|
|
|
|
|
0
|
$mtllib =~ s/[\\\:]/\//g; |
|
126
|
0
|
|
|
|
|
0
|
$obj->{mtllib} = $mtllib; |
|
127
|
0
|
|
|
|
|
0
|
$obj->ReadMtlLib; |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
elsif (/^vt\s+/) { # UV/UVW line |
|
130
|
0
|
|
|
|
|
0
|
/^vt\s+([\d\+\-eE\.]+)\s+([\d\+\-eE\.]+)\s*([\d\+\-eE\.]*)/; |
|
131
|
0
|
|
|
|
|
0
|
my $u = $1 + 0; |
|
132
|
0
|
|
|
|
|
0
|
my $v = $2 + 0; |
|
133
|
0
|
|
|
|
|
0
|
my $w = $3 + 0; |
|
134
|
0
|
|
|
|
|
0
|
push @{$obj->{vt}}, {u => $u, |
|
|
0
|
|
|
|
|
0
|
|
|
135
|
|
|
|
|
|
|
v => $v, |
|
136
|
|
|
|
|
|
|
w => $w, |
|
137
|
|
|
|
|
|
|
id => $vtoid}; |
|
138
|
0
|
|
|
|
|
0
|
$vtoid++; |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
elsif (/^vn\s+/) { |
|
141
|
0
|
|
|
|
|
0
|
/^vn\s+([\d\+\-eE\.]+)\s+([\d\+\-eE\.]+)\s+([\d\+\-eE\.]+)/; |
|
142
|
0
|
|
|
|
|
0
|
my $i = $1 + 0; |
|
143
|
0
|
|
|
|
|
0
|
my $j = $2 + 0; |
|
144
|
0
|
|
|
|
|
0
|
my $k = $2 + 0; |
|
145
|
0
|
|
|
|
|
0
|
push @{$obj->{vn}}, {i => $i, |
|
|
0
|
|
|
|
|
0
|
|
|
146
|
|
|
|
|
|
|
j => $j, |
|
147
|
|
|
|
|
|
|
k => $k, |
|
148
|
|
|
|
|
|
|
id => $vnoid}; |
|
149
|
0
|
|
|
|
|
0
|
$vnoid++; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
elsif (/^fo?\s+(.*)$/) { # Polygon line |
|
152
|
0
|
|
|
|
|
0
|
my $p = $1; |
|
153
|
0
|
|
|
|
|
0
|
my @poly = split " ", $p; |
|
154
|
0
|
|
|
|
|
0
|
my @p; |
|
155
|
0
|
|
|
|
|
0
|
for my $pv (@poly) { |
|
156
|
0
|
|
|
|
|
0
|
my ($v, $vt, $vn) = split /\//, $pv; |
|
157
|
|
|
|
|
|
|
# OBJ files are 1-indexed. We want the right element |
|
158
|
|
|
|
|
|
|
# BUT counting backwards is as we expect. |
|
159
|
0
|
0
|
|
|
|
0
|
$v-- if $v > 0; |
|
160
|
0
|
0
|
|
|
|
0
|
$vt-- if $vt > 0; |
|
161
|
0
|
0
|
|
|
|
0
|
$vn-- if $vn > 0; |
|
162
|
0
|
|
|
|
|
0
|
push @p, {v => $obj->{v}->[$v], |
|
163
|
|
|
|
|
|
|
vt => $obj->{vt}->[$vt], |
|
164
|
|
|
|
|
|
|
vn => $obj->{vn}->[$vn], |
|
165
|
|
|
|
|
|
|
g => $obj->{_group}, |
|
166
|
|
|
|
|
|
|
m => $obj->{_material}, |
|
167
|
|
|
|
|
|
|
r => $obj->{_region}}; |
|
168
|
0
|
0
|
|
|
|
0
|
push @{$obj->{group}->{$obj->{_group}}}, |
|
|
0
|
|
|
|
|
0
|
|
|
169
|
|
|
|
|
|
|
{v => $obj->{v}->[$v], |
|
170
|
|
|
|
|
|
|
vt => $obj->{vt}->[$vt], |
|
171
|
|
|
|
|
|
|
vn => $obj->{vn}->[$vn], |
|
172
|
|
|
|
|
|
|
m => $obj->{_material}, |
|
173
|
|
|
|
|
|
|
r => $obj->{_region}} |
|
174
|
|
|
|
|
|
|
unless $obj->{seengroupv}->{$obj->{_group}}->{$v}; |
|
175
|
0
|
|
|
|
|
0
|
$obj->{seengroupv}->{$obj->{_group}}->{$v} = 1; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
0
|
|
|
|
|
0
|
push @{$obj->{f}}, {verts => \@p, |
|
|
0
|
|
|
|
|
0
|
|
|
178
|
|
|
|
|
|
|
group => $obj->{_group}, |
|
179
|
|
|
|
|
|
|
material => $obj->{_material}, |
|
180
|
|
|
|
|
|
|
region => $obj->{_region}}; |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# Theoretically, you can now get the x, y, and z coordinates and |
|
183
|
|
|
|
|
|
|
# UV coordinates and group and material for, say, the third vertex |
|
184
|
|
|
|
|
|
|
# in the 9th facet like so: |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# $x = $obj->{f}->[10]->{verts}->[2]->{v}->{x}; |
|
187
|
|
|
|
|
|
|
# $y = $obj->{f}->[10]->{verts}->[2]->{v}->{y}; |
|
188
|
|
|
|
|
|
|
# $z = $obj->{f}->[10]->{verts}->[2]->{v}->{z}; |
|
189
|
|
|
|
|
|
|
# $g = $obj->{f}->[10]->{group}; |
|
190
|
|
|
|
|
|
|
# $m = $obj->{f}->[10]->{material}; |
|
191
|
|
|
|
|
|
|
# $u = $obj->{f}->[10]->{verts}->[2]->{vt}->{u}; |
|
192
|
|
|
|
|
|
|
# $v = $obj->{f}->[10]->{verts}->[2]->{vt}->{v}; |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# Or, to make it even easier: |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# $fv = $obj->{f}->[10]->{verts}->[2]; |
|
197
|
|
|
|
|
|
|
# $y = $fv->{v}->{y}; |
|
198
|
|
|
|
|
|
|
# $u = $fv->{vt}->{u}; |
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
elsif (/^l\s+(.*)$/) { # Line line |
|
201
|
0
|
|
|
|
|
0
|
my $l = $1; |
|
202
|
0
|
|
|
|
|
0
|
my @line = split " ", $l; |
|
203
|
0
|
|
|
|
|
0
|
my @l; |
|
204
|
0
|
|
|
|
|
0
|
for my $lv (@line) { |
|
205
|
0
|
|
|
|
|
0
|
my ($v, $vt) = split /\//, $lv; |
|
206
|
0
|
0
|
|
|
|
0
|
$v-- if $v > 0; |
|
207
|
0
|
0
|
|
|
|
0
|
$vt-- if $vt > 0; |
|
208
|
0
|
|
|
|
|
0
|
push @l, {v => $obj->{v}->[$v], |
|
209
|
|
|
|
|
|
|
vt => $obj->{vt}->[$vt]}; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
0
|
|
|
|
|
0
|
push @{$obj->{l}}, \@l; |
|
|
0
|
|
|
|
|
0
|
|
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
elsif (/^p\s+(.*)$/) { # Point line |
|
214
|
0
|
|
|
|
|
0
|
my $v = $1; |
|
215
|
0
|
0
|
|
|
|
0
|
$v-- if $v > 0; |
|
216
|
0
|
|
|
|
|
0
|
push @{$obj->{p}}, $v; |
|
|
0
|
|
|
|
|
0
|
|
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
elsif (/^\s*#\s*(.*)$/) { # comment |
|
219
|
0
|
|
|
|
|
0
|
push @{$obj->{comments}}, $1; |
|
|
0
|
|
|
|
|
0
|
|
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
} |
|
222
|
0
|
|
|
|
|
0
|
close $OBJ; |
|
223
|
0
|
|
|
|
|
0
|
return 1; |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub ReadMtlLib { |
|
227
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
228
|
0
|
|
|
|
|
0
|
my $mtllib = shift; |
|
229
|
0
|
|
|
|
|
0
|
$obj->{mtllib} = $mtllib; |
|
230
|
0
|
0
|
|
|
|
0
|
return undef unless $mtllib; |
|
231
|
0
|
|
|
|
|
0
|
my $MTL; |
|
232
|
0
|
0
|
|
|
|
0
|
unless (open ($MTL, "$mtllib")) { |
|
233
|
0
|
|
|
|
|
0
|
$obj->{errstr} = "Can't read material library $mtllib."; |
|
234
|
0
|
|
|
|
|
0
|
return undef; |
|
235
|
|
|
|
|
|
|
} |
|
236
|
0
|
|
|
|
|
0
|
while (<$MTL>) { |
|
237
|
0
|
|
|
|
|
0
|
chomp; |
|
238
|
0
|
|
|
|
|
0
|
s/\r//; |
|
239
|
0
|
|
|
|
|
0
|
s/^\s+//; |
|
240
|
0
|
|
|
|
|
0
|
s/\s+$//; |
|
241
|
0
|
0
|
|
|
|
0
|
if (/^newmtl\s+(\S+)/) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
242
|
0
|
|
|
|
|
0
|
$obj->{_defmtl} = $1; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
elsif (/^Ka\s+([\d\.eE\-\+]+)\s+([[\d\.eE\-\+]+)\s+([[\d\.eE\-\+]+)/) { |
|
245
|
0
|
|
|
|
|
0
|
my $r = $1; |
|
246
|
0
|
|
|
|
|
0
|
my $g = $2; |
|
247
|
0
|
|
|
|
|
0
|
my $b = $3; |
|
248
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Ka}->{r} = $r * 255; |
|
249
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Ka}->{g} = $g * 255; |
|
250
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Ka}->{b} = $b * 255; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
elsif (/^Kd\s+([\d\.eE\-\+]+)\s+([[\d\.eE\-\+]+)\s+([[\d\.eE\-\+]+)/) { |
|
253
|
0
|
|
|
|
|
0
|
my $r = $1; |
|
254
|
0
|
|
|
|
|
0
|
my $g = $2; |
|
255
|
0
|
|
|
|
|
0
|
my $b = $3; |
|
256
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Kd}->{r} = $r * 255; |
|
257
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Kd}->{g} = $g * 255; |
|
258
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Kd}->{b} = $b * 255; |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
elsif (/^Ks\s+([\d\.eE\-\+]+)\s+([[\d\.eE\-\+]+)\s+([[\d\.eE\-\+]+)/) { |
|
261
|
0
|
|
|
|
|
0
|
my $r = $1; |
|
262
|
0
|
|
|
|
|
0
|
my $g = $2; |
|
263
|
0
|
|
|
|
|
0
|
my $b = $3; |
|
264
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Ks}->{r} = $r * 255; |
|
265
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Ks}->{g} = $g * 255; |
|
266
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Ks}->{b} = $b * 255; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
elsif (/^illum\s+(\d)/) { |
|
269
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{illum} = $1 + 0; |
|
270
|
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
elsif (/^Ns\s+([\d\.eE\-\+]+)/) { |
|
272
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Ns} = $1 + 0; |
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
elsif (/^(d|Tr)\s+([\d\.eE\-\+]+)/) { |
|
275
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{Tr} = $1 + 0; |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
elsif (/^map_Ka\s+(.*)/) { |
|
278
|
0
|
|
|
|
|
0
|
$obj->{mtl}->{$obj->{_defmtl}}->{textureMap} = $1; |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
} |
|
281
|
0
|
|
|
|
|
0
|
close $MTL; |
|
282
|
0
|
|
|
|
|
0
|
return 1; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub Translate { |
|
286
|
1
|
|
|
1
|
1
|
3
|
my $obj = shift; |
|
287
|
1
|
|
|
|
|
2
|
my $trans; |
|
288
|
1
|
|
|
|
|
5
|
while (@_) { |
|
289
|
3
|
|
|
|
|
5
|
my $axis = shift; |
|
290
|
3
|
|
|
|
|
5
|
my $amount = shift; |
|
291
|
3
|
|
|
|
|
9
|
$trans->{$axis} = $amount + 0; |
|
292
|
|
|
|
|
|
|
} |
|
293
|
1
|
|
|
|
|
2
|
for my $v (@{$obj->{v}}) { |
|
|
1
|
|
|
|
|
3
|
|
|
294
|
0
|
0
|
|
|
|
0
|
if ($trans->{x}) { |
|
295
|
0
|
|
|
|
|
0
|
$v->{x} += $trans->{x}; |
|
296
|
|
|
|
|
|
|
} |
|
297
|
0
|
0
|
|
|
|
0
|
if ($trans->{y}) { |
|
298
|
0
|
|
|
|
|
0
|
$v->{y} += $trans->{y}; |
|
299
|
|
|
|
|
|
|
} |
|
300
|
0
|
0
|
|
|
|
0
|
if ($trans->{z}) { |
|
301
|
0
|
|
|
|
|
0
|
$v->{z} += $trans->{z}; |
|
302
|
|
|
|
|
|
|
} |
|
303
|
|
|
|
|
|
|
} |
|
304
|
1
|
|
|
|
|
5
|
return 1; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub _getTransCentre { |
|
308
|
2
|
|
|
2
|
|
4
|
my $obj = shift; |
|
309
|
2
|
|
|
|
|
7
|
my $centre = {x => 0, |
|
310
|
|
|
|
|
|
|
y => 0, |
|
311
|
|
|
|
|
|
|
z => 0}; |
|
312
|
2
|
|
|
|
|
4
|
my $c = shift; |
|
313
|
2
|
50
|
|
|
|
10
|
return $centre unless $c; |
|
314
|
0
|
0
|
|
|
|
0
|
return $obj->GetNaturalCentre if $c eq 'natural'; |
|
315
|
0
|
0
|
|
|
|
0
|
return $obj->GetApparentCentre if $c eq 'apparent'; |
|
316
|
0
|
|
|
|
|
0
|
my @stdrot = qw(x y z); |
|
317
|
0
|
0
|
0
|
|
|
0
|
if (ref $c and ref $c ne 'SCALAR') { |
|
318
|
|
|
|
|
|
|
# They can use an arrayref like center => [x,y,z] |
|
319
|
0
|
0
|
|
|
|
0
|
if (ref $c eq 'ARRAY') { |
|
|
|
0
|
|
|
|
|
|
|
320
|
0
|
|
|
|
|
0
|
for my $p (@{$c}) { |
|
|
0
|
|
|
|
|
0
|
|
|
321
|
0
|
|
|
|
|
0
|
my $ax = shift @stdrot; |
|
322
|
0
|
|
|
|
|
0
|
$centre->{$ax} = $p; |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
} |
|
325
|
|
|
|
|
|
|
# ...or a hashref like center => {x => x, y => y, z => z} |
|
326
|
|
|
|
|
|
|
elsif (ref $c eq 'HASH') { |
|
327
|
0
|
|
|
|
|
0
|
for my $k (keys %{$c}) { |
|
|
0
|
|
|
|
|
0
|
|
|
328
|
0
|
|
|
|
|
0
|
$centre->{$k} = $c->{$k}; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
} |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
else { |
|
333
|
|
|
|
|
|
|
# Or a scalarref like center => \$center |
|
334
|
0
|
0
|
0
|
|
|
0
|
if (ref $c and ref $c eq 'SCALAR') { |
|
335
|
0
|
|
|
|
|
0
|
$c = ${$c}; |
|
|
0
|
|
|
|
|
0
|
|
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
# or a real scalar in two ways: |
|
338
|
0
|
|
|
|
|
0
|
$c =~ s/\s+//g; # (ignoring whitespace) |
|
339
|
0
|
|
|
|
|
0
|
my @c = split /,/, $c; |
|
340
|
0
|
|
|
|
|
0
|
for my $p (@c) { |
|
341
|
0
|
|
|
|
|
0
|
my ($ax, $r); |
|
342
|
|
|
|
|
|
|
# Either like 'x:x,y:y,z:z' |
|
343
|
0
|
0
|
|
|
|
0
|
if ($p =~ /:/) { |
|
344
|
0
|
|
|
|
|
0
|
($ax, $r) = split /:/, $p; |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
# ...or like 'x,y,z' |
|
347
|
|
|
|
|
|
|
else { |
|
348
|
0
|
|
|
|
|
0
|
$ax = shift @stdrot; |
|
349
|
0
|
|
|
|
|
0
|
$r = $p; |
|
350
|
|
|
|
|
|
|
} |
|
351
|
0
|
|
|
|
|
0
|
$centre->{$ax} = $r; |
|
352
|
|
|
|
|
|
|
} |
|
353
|
|
|
|
|
|
|
} |
|
354
|
0
|
|
|
|
|
0
|
return $centre; |
|
355
|
|
|
|
|
|
|
} |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub GetNaturalCentre { |
|
358
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
359
|
0
|
|
|
|
|
0
|
my $vcount = scalar @{$obj->{v}}; |
|
|
0
|
|
|
|
|
0
|
|
|
360
|
0
|
|
|
|
|
0
|
my $centre = {x => 0, |
|
361
|
|
|
|
|
|
|
y => 0, |
|
362
|
|
|
|
|
|
|
z => 0}; |
|
363
|
0
|
0
|
|
|
|
0
|
return $centre unless $vcount; |
|
364
|
0
|
|
|
|
|
0
|
my ($x, $y, $z) = (0,0,0); |
|
365
|
0
|
|
|
|
|
0
|
for my $v (@{$obj->{v}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
366
|
0
|
|
|
|
|
0
|
$x += $v->{x}; |
|
367
|
0
|
|
|
|
|
0
|
$y += $v->{y}; |
|
368
|
0
|
|
|
|
|
0
|
$z += $v->{z}; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
0
|
|
|
|
|
0
|
$centre->{x} = $x / $vcount; |
|
371
|
0
|
|
|
|
|
0
|
$centre->{y} = $y / $vcount; |
|
372
|
0
|
|
|
|
|
0
|
$centre->{z} = $z / $vcount; |
|
373
|
0
|
|
|
|
|
0
|
return $centre; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub GetApparentCentre { |
|
377
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
378
|
0
|
|
|
|
|
0
|
my $center = {x => 0, |
|
379
|
|
|
|
|
|
|
y => 0, |
|
380
|
|
|
|
|
|
|
z => 0}; |
|
381
|
0
|
0
|
|
|
|
0
|
return $center unless scalar @{$obj->{v}}; |
|
|
0
|
|
|
|
|
0
|
|
|
382
|
0
|
|
|
|
|
0
|
my ($min, $max) = $obj->MinMax; |
|
383
|
0
|
|
|
|
|
0
|
$center->{x} = $max->{x} + $min->{x} / 2; |
|
384
|
0
|
|
|
|
|
0
|
$center->{y} = $max->{y} + $min->{y} / 2; |
|
385
|
0
|
|
|
|
|
0
|
$center->{z} = $max->{z} + $min->{z} / 2; |
|
386
|
0
|
|
|
|
|
0
|
return $center; |
|
387
|
|
|
|
|
|
|
} |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
sub MinMax { |
|
390
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
391
|
0
|
|
|
|
|
0
|
my $max = {x => 0, |
|
392
|
|
|
|
|
|
|
y => 0, |
|
393
|
|
|
|
|
|
|
z => 0}; |
|
394
|
0
|
|
|
|
|
0
|
my $min = {x => 0, |
|
395
|
|
|
|
|
|
|
y => 0, |
|
396
|
|
|
|
|
|
|
z => 0}; |
|
397
|
0
|
0
|
|
|
|
0
|
return ($min, $max) unless scalar @{$obj->{v}}; |
|
|
0
|
|
|
|
|
0
|
|
|
398
|
0
|
|
|
|
|
0
|
for my $v (@{$obj->{v}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
399
|
0
|
0
|
|
|
|
0
|
$max->{x} = $v->{x} if $v->{x} > $max->{x}; |
|
400
|
0
|
0
|
|
|
|
0
|
$min->{x} = $v->{x} if $v->{x} < $min->{x}; |
|
401
|
0
|
0
|
|
|
|
0
|
$max->{y} = $v->{y} if $v->{y} > $max->{y}; |
|
402
|
0
|
0
|
|
|
|
0
|
$min->{y} = $v->{y} if $v->{y} < $min->{y}; |
|
403
|
0
|
0
|
|
|
|
0
|
$max->{z} = $v->{z} if $v->{z} > $max->{z}; |
|
404
|
0
|
0
|
|
|
|
0
|
$min->{z} = $v->{z} if $v->{z} < $min->{z}; |
|
405
|
|
|
|
|
|
|
} |
|
406
|
0
|
|
|
|
|
0
|
return ($min, $max); |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub Top { |
|
410
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
411
|
0
|
|
|
|
|
0
|
my ($min, $max) = $obj->MinMax; |
|
412
|
0
|
|
|
|
|
0
|
return $max->{y}; |
|
413
|
|
|
|
|
|
|
} |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
sub Bottom { |
|
416
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
417
|
0
|
|
|
|
|
0
|
my ($min, $max) = $obj->MinMax; |
|
418
|
0
|
|
|
|
|
0
|
return $min->{y}; |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub Left { |
|
422
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
423
|
0
|
|
|
|
|
0
|
my ($min, $max) = $obj->MinMax; |
|
424
|
0
|
|
|
|
|
0
|
return $min->{x}; |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
sub Right { |
|
428
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
429
|
0
|
|
|
|
|
0
|
my ($min, $max) = $obj->MinMax; |
|
430
|
0
|
|
|
|
|
0
|
return $max->{x}; |
|
431
|
|
|
|
|
|
|
} |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub Front { |
|
434
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
435
|
0
|
|
|
|
|
0
|
my ($min, $max) = $obj->MinMax; |
|
436
|
0
|
|
|
|
|
0
|
return $max->{z}; |
|
437
|
|
|
|
|
|
|
} |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub Back { |
|
440
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
441
|
0
|
|
|
|
|
0
|
my ($min, $max) = $obj->MinMax; |
|
442
|
0
|
|
|
|
|
0
|
return $min->{z}; |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub ReverseWinding { |
|
446
|
1
|
|
|
1
|
1
|
1
|
my $obj = shift; |
|
447
|
1
|
50
|
|
|
|
2
|
unless (scalar @{$obj->{f}}) { |
|
|
1
|
|
|
|
|
5
|
|
|
448
|
1
|
|
|
|
|
4
|
$obj->{errstr} = 'This object has no facet information'; |
|
449
|
1
|
|
|
|
|
5
|
return undef; |
|
450
|
|
|
|
|
|
|
} |
|
451
|
0
|
|
|
|
|
0
|
for my $f (@{$obj->{f}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
452
|
0
|
|
|
|
|
0
|
$f->{verts} = [reverse @{$f->{verts}}]; |
|
|
0
|
|
|
|
|
0
|
|
|
453
|
|
|
|
|
|
|
} |
|
454
|
0
|
|
|
|
|
0
|
return 1; |
|
455
|
|
|
|
|
|
|
} |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
sub Rotate { |
|
458
|
1
|
|
|
1
|
1
|
680
|
my $obj = shift; |
|
459
|
1
|
|
|
|
|
2
|
my $rot; |
|
460
|
1
|
|
|
|
|
4
|
while (@_) { |
|
461
|
3
|
|
|
|
|
4
|
my $axis = shift; |
|
462
|
3
|
|
|
|
|
4
|
my $amount = shift; |
|
463
|
3
|
|
|
|
|
11
|
$rot->{$axis} = $amount + 0; |
|
464
|
|
|
|
|
|
|
} |
|
465
|
1
|
|
33
|
|
|
9
|
my $centre = $obj->_getTransCentre($rot->{centre} || $rot->{center}); |
|
466
|
1
|
50
|
|
|
|
4
|
return undef unless $rot; |
|
467
|
1
|
|
|
|
|
2
|
for my $v (@{$obj->{v}}) { |
|
|
1
|
|
|
|
|
5
|
|
|
468
|
0
|
0
|
0
|
|
|
0
|
if ($centre->{x} || $centre->{y} || $centre->{z}) { |
|
|
|
|
0
|
|
|
|
|
|
469
|
0
|
0
|
|
|
|
0
|
if ($centre->{x}) { |
|
470
|
0
|
|
|
|
|
0
|
$v->{x} -= $centre->{x}; |
|
471
|
|
|
|
|
|
|
} |
|
472
|
0
|
0
|
|
|
|
0
|
if ($centre->{y}) { |
|
473
|
0
|
|
|
|
|
0
|
$v->{y} -= $centre->{y}; |
|
474
|
|
|
|
|
|
|
} |
|
475
|
0
|
0
|
|
|
|
0
|
if ($centre->{z}) { |
|
476
|
0
|
|
|
|
|
0
|
$v->{z} -= $centre->{z}; |
|
477
|
|
|
|
|
|
|
} |
|
478
|
|
|
|
|
|
|
} |
|
479
|
0
|
0
|
|
|
|
0
|
if ($rot->{x}) { |
|
480
|
0
|
|
|
|
|
0
|
my $rad = Math::Trig::deg2rad($rot->{x}); |
|
481
|
0
|
|
|
|
|
0
|
my ($rho, $theta, $phi) |
|
482
|
|
|
|
|
|
|
= Math::Trig::cartesian_to_spherical($v->{y}, $v->{z}, 0); |
|
483
|
0
|
|
|
|
|
0
|
$theta += $rad; |
|
484
|
0
|
|
|
|
|
0
|
($v->{y}, $v->{z}, undef) |
|
485
|
|
|
|
|
|
|
= Math::Trig::spherical_to_cartesian($rho, $theta, $phi); |
|
486
|
|
|
|
|
|
|
} |
|
487
|
0
|
0
|
|
|
|
0
|
if ($rot->{y}) { |
|
488
|
0
|
|
|
|
|
0
|
my $rad = Math::Trig::deg2rad($rot->{y}); |
|
489
|
0
|
|
|
|
|
0
|
my ($rho, $theta, $phi) |
|
490
|
|
|
|
|
|
|
= Math::Trig::cartesian_to_spherical($v->{x}, $v->{z}, 0); |
|
491
|
0
|
|
|
|
|
0
|
$theta += $rad; |
|
492
|
0
|
|
|
|
|
0
|
($v->{x}, $v->{z}, undef) |
|
493
|
|
|
|
|
|
|
= Math::Trig::spherical_to_cartesian($rho, $theta, $phi); |
|
494
|
|
|
|
|
|
|
} |
|
495
|
0
|
0
|
|
|
|
0
|
if ($rot->{z}) { |
|
496
|
0
|
|
|
|
|
0
|
my $rad = Math::Trig::deg2rad($rot->{z}); |
|
497
|
0
|
|
|
|
|
0
|
my ($rho, $theta, $phi) |
|
498
|
|
|
|
|
|
|
= Math::Trig::cartesian_to_spherical($v->{x}, $v->{y}, 0); |
|
499
|
0
|
|
|
|
|
0
|
$theta += $rad; |
|
500
|
0
|
|
|
|
|
0
|
($v->{x}, $v->{y}, undef) |
|
501
|
|
|
|
|
|
|
= Math::Trig::spherical_to_cartesian($rho, $theta, $phi); |
|
502
|
|
|
|
|
|
|
} |
|
503
|
0
|
0
|
0
|
|
|
0
|
if ($centre->{x} || $centre->{y} || $centre->{z}) { |
|
|
|
|
0
|
|
|
|
|
|
504
|
0
|
0
|
|
|
|
0
|
if ($centre->{x}) { |
|
505
|
0
|
|
|
|
|
0
|
$v->{x} += $centre->{x}; |
|
506
|
|
|
|
|
|
|
} |
|
507
|
0
|
0
|
|
|
|
0
|
if ($centre->{y}) { |
|
508
|
0
|
|
|
|
|
0
|
$v->{y} += $centre->{y}; |
|
509
|
|
|
|
|
|
|
} |
|
510
|
0
|
0
|
|
|
|
0
|
if ($centre->{z}) { |
|
511
|
0
|
|
|
|
|
0
|
$v->{z} += $centre->{z}; |
|
512
|
|
|
|
|
|
|
} |
|
513
|
|
|
|
|
|
|
} |
|
514
|
|
|
|
|
|
|
} |
|
515
|
1
|
|
|
|
|
6
|
return 1; |
|
516
|
|
|
|
|
|
|
} |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub _getScaleVal { |
|
519
|
3
|
|
|
3
|
|
5
|
my $obj= shift; |
|
520
|
3
|
|
|
|
|
4
|
my $sv = shift; |
|
521
|
3
|
50
|
|
|
|
7
|
return 1 unless $sv; |
|
522
|
3
|
|
|
|
|
3
|
my $op; |
|
523
|
3
|
|
|
|
|
7
|
$sv =~ s/([\+\-])//; |
|
524
|
3
|
|
|
|
|
5
|
$op = $1; |
|
525
|
3
|
50
|
|
|
|
15
|
if ($sv =~ s/\%$//) { |
|
526
|
3
|
|
|
|
|
7
|
$sv /= 100; |
|
527
|
|
|
|
|
|
|
} |
|
528
|
3
|
50
|
|
|
|
7
|
if ($op) { |
|
529
|
0
|
0
|
|
|
|
0
|
if ($op eq '-') { |
|
|
|
0
|
|
|
|
|
|
|
530
|
0
|
|
|
|
|
0
|
$sv = 1 - $sv; |
|
531
|
|
|
|
|
|
|
} |
|
532
|
|
|
|
|
|
|
elsif ($op eq '+') { |
|
533
|
0
|
|
|
|
|
0
|
$sv = 1 + $sv; |
|
534
|
|
|
|
|
|
|
} |
|
535
|
|
|
|
|
|
|
} |
|
536
|
3
|
|
|
|
|
7
|
return $sv; |
|
537
|
|
|
|
|
|
|
} |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
sub Scale { |
|
540
|
1
|
|
|
1
|
1
|
3
|
my $obj = shift; |
|
541
|
1
|
|
|
|
|
4
|
my $scale = {x => 1, |
|
542
|
|
|
|
|
|
|
y => 1, |
|
543
|
|
|
|
|
|
|
z => 1}; |
|
544
|
1
|
50
|
|
|
|
21
|
if (scalar @_ > 1) { |
|
545
|
0
|
|
|
|
|
0
|
while (@_) { |
|
546
|
0
|
|
|
|
|
0
|
my $axis = shift; |
|
547
|
0
|
|
|
|
|
0
|
my $amount = $obj->_getScaleVal(shift); |
|
548
|
0
|
|
|
|
|
0
|
$scale->{$axis} = $amount; |
|
549
|
|
|
|
|
|
|
} |
|
550
|
|
|
|
|
|
|
} |
|
551
|
|
|
|
|
|
|
else { |
|
552
|
1
|
|
|
|
|
3
|
my $s = shift; |
|
553
|
1
|
|
|
|
|
4
|
$scale->{x} = $obj->_getScaleVal($s); |
|
554
|
1
|
|
|
|
|
3
|
$scale->{y} = $obj->_getScaleVal($s); |
|
555
|
1
|
|
|
|
|
4
|
$scale->{z} = $obj->_getScaleVal($s); |
|
556
|
|
|
|
|
|
|
} |
|
557
|
1
|
50
|
|
|
|
5
|
if ($scale->{scale}) { |
|
558
|
0
|
|
|
|
|
0
|
$scale->{scale} = $obj->_getScaleVal($scale->{scale}); |
|
559
|
0
|
|
0
|
|
|
0
|
$scale->{x} ||= $scale->{scale}; |
|
560
|
0
|
|
0
|
|
|
0
|
$scale->{y} ||= $scale->{scale}; |
|
561
|
0
|
|
0
|
|
|
0
|
$scale->{z} ||= $scale->{scale}; |
|
562
|
|
|
|
|
|
|
} |
|
563
|
1
|
|
33
|
|
|
11
|
my $centre = $obj->_getTransCentre($scale->{centre} || $scale->{center}); |
|
564
|
1
|
|
|
|
|
1
|
for my $v (@{$obj->{v}}) { |
|
|
1
|
|
|
|
|
5
|
|
|
565
|
0
|
|
|
|
|
0
|
$v->{x} *= $scale->{x}; |
|
566
|
0
|
|
|
|
|
0
|
$v->{y} *= $scale->{y}; |
|
567
|
0
|
|
|
|
|
0
|
$v->{z} *= $scale->{z}; |
|
568
|
|
|
|
|
|
|
} |
|
569
|
1
|
|
|
|
|
5
|
return 1; |
|
570
|
|
|
|
|
|
|
} |
|
571
|
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
sub GetVertex { |
|
573
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
574
|
0
|
|
|
|
|
0
|
my $vert = shift; |
|
575
|
0
|
0
|
|
|
|
0
|
unless ($vert) { |
|
576
|
0
|
|
|
|
|
0
|
$obj->{errstr} = 'No vertex specified'; |
|
577
|
0
|
|
|
|
|
0
|
return undef; |
|
578
|
|
|
|
|
|
|
} |
|
579
|
0
|
0
|
|
|
|
0
|
unless (exists $obj->{v}->[$vert]) { |
|
580
|
0
|
|
|
|
|
0
|
$obj->{errstr} = "Vertex $vert does not exist"; |
|
581
|
0
|
|
|
|
|
0
|
return undef; |
|
582
|
|
|
|
|
|
|
} |
|
583
|
0
|
0
|
|
|
|
0
|
return wantarray ? ($obj->{v}->[$vert]->{x}, |
|
584
|
|
|
|
|
|
|
$obj->{v}->[$vert]->{y}, |
|
585
|
|
|
|
|
|
|
$obj->{v}->[$vert]->{z}) |
|
586
|
|
|
|
|
|
|
: $obj->{v}->[$vert]; |
|
587
|
|
|
|
|
|
|
} |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
sub GetVertexSpherical { |
|
590
|
0
|
|
|
0
|
1
|
0
|
my $obj = shift; |
|
591
|
0
|
|
|
|
|
0
|
my $vert = shift; |
|
592
|
0
|
0
|
|
|
|
0
|
unless ($vert) { |
|
593
|
0
|
|
|
|
|
0
|
$obj->{errstr} = 'No vertex specified'; |
|
594
|
0
|
|
|
|
|
0
|
return undef; |
|
595
|
|
|
|
|
|
|
} |
|
596
|
0
|
0
|
|
|
|
0
|
unless (exists $obj->{v}->[$vert]) { |
|
597
|
0
|
|
|
|
|
0
|
$obj->{errstr} = "Vertex $vert does not exist"; |
|
598
|
0
|
|
|
|
|
0
|
return undef; |
|
599
|
|
|
|
|
|
|
} |
|
600
|
0
|
|
|
|
|
0
|
my $v = $obj->{v}->[$vert]; |
|
601
|
0
|
|
|
|
|
0
|
my ($rho, $theta, $phi) |
|
602
|
|
|
|
|
|
|
= Math::Trig::cartesian_to_spherical($v->{x}, $v->{y}, $obj->{z}); |
|
603
|
0
|
|
|
|
|
0
|
$theta = Math::Trig::rad2deg($theta); |
|
604
|
0
|
|
|
|
|
0
|
$phi = Math::Trig::rad2deg($phi); |
|
605
|
0
|
0
|
|
|
|
0
|
return wantarray ? ($rho, $theta, $phi) : {rho => $rho, |
|
606
|
|
|
|
|
|
|
theta => $theta, |
|
607
|
|
|
|
|
|
|
phi => $phi}; |
|
608
|
|
|
|
|
|
|
} |
|
609
|
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub Mirror { |
|
611
|
1
|
|
|
1
|
1
|
3
|
my $obj = shift; |
|
612
|
1
|
|
|
|
|
2
|
my $ax = shift; |
|
613
|
1
|
|
50
|
|
|
4
|
$ax ||= 'x'; |
|
614
|
1
|
|
|
|
|
2
|
for my $v (@{$obj->{v}}) { |
|
|
1
|
|
|
|
|
3
|
|
|
615
|
0
|
|
|
|
|
0
|
$v->{$ax} = 0 - $v->{ax}; |
|
616
|
|
|
|
|
|
|
} |
|
617
|
1
|
|
|
|
|
4
|
$obj->ReverseWinding; |
|
618
|
1
|
|
|
|
|
3
|
return 1; |
|
619
|
|
|
|
|
|
|
} |
|
620
|
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
sub FlipUVs { |
|
622
|
0
|
|
|
0
|
1
|
|
my $obj = shift; |
|
623
|
0
|
|
|
|
|
|
my $ax = shift; |
|
624
|
0
|
|
0
|
|
|
|
$ax ||= 'u'; |
|
625
|
0
|
|
|
|
|
|
for my $vt (@{$obj->{vt}}) { |
|
|
0
|
|
|
|
|
|
|
|
626
|
0
|
|
|
|
|
|
$vt->{$ax} = 1 - $vt->{$ax}; |
|
627
|
|
|
|
|
|
|
} |
|
628
|
0
|
|
|
|
|
|
return 1; |
|
629
|
|
|
|
|
|
|
} |
|
630
|
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
sub WriteObj { |
|
632
|
0
|
|
|
0
|
1
|
|
my $obj = shift; |
|
633
|
0
|
|
0
|
|
|
|
my $outfile = shift || $obj->{outfile}; |
|
634
|
0
|
|
|
|
|
|
$obj->{outfile} = $outfile; |
|
635
|
|
|
|
|
|
|
|
|
636
|
0
|
|
|
|
|
|
my $OBJ; |
|
637
|
0
|
|
|
|
|
|
my $was_stdout = 0; |
|
638
|
0
|
0
|
|
|
|
|
if ($obj->{outfile}) { |
|
639
|
0
|
|
|
|
|
|
open $OBJ, ">$obj->{outfile}"; |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
else { |
|
642
|
0
|
|
|
|
|
|
$was_stdout = 1; |
|
643
|
0
|
|
|
|
|
|
$OBJ = *STDOUT{IO}; |
|
644
|
|
|
|
|
|
|
} |
|
645
|
|
|
|
|
|
|
|
|
646
|
0
|
|
0
|
|
|
|
my $prec = $obj->{prec} || 8; |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
# Print out file comments |
|
649
|
0
|
|
|
|
|
|
unshift @{$obj->{comments}}, |
|
|
0
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
"File generated by MapShape.pl (c) Dodger", |
|
651
|
0
|
|
|
|
|
|
scalar @{$obj->{v}} . ' Vertices', |
|
652
|
0
|
|
|
|
|
|
scalar @{$obj->{vt}} . ' UVs', |
|
653
|
0
|
|
|
|
|
|
scalar @{$obj->{f}} . ' Polygons', |
|
654
|
0
|
|
|
|
|
|
scalar(keys(%{$obj->{g}})) . ' Groups', |
|
655
|
0
|
|
|
|
|
|
scalar(keys(%{$obj->{mtl}})) . 'Materials', |
|
656
|
0
|
|
|
|
|
|
scalar(keys(%{$obj->{r}})) . 'Regions'; |
|
657
|
0
|
|
|
|
|
|
for my $comment (@{$obj->{comments}}) { |
|
|
0
|
|
|
|
|
|
|
|
658
|
0
|
|
|
|
|
|
print {$OBJ} "# $comment\n"; |
|
|
0
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
} |
|
660
|
0
|
|
|
|
|
|
print {$OBJ} "\n"; |
|
|
0
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
# Print out vertices |
|
663
|
0
|
|
|
|
|
|
for my $v (@{$obj->{v}}) { |
|
|
0
|
|
|
|
|
|
|
|
664
|
0
|
|
|
|
|
|
my $pf = "v %.${prec}f %.${prec}f %.${prec}f\n"; |
|
665
|
0
|
|
|
|
|
|
printf {$OBJ} $pf, $v->{x}, $v->{y}, $v->{z}; |
|
|
0
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
} |
|
667
|
0
|
|
|
|
|
|
print {$OBJ} "\n"; |
|
|
0
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# Print out UVs |
|
670
|
0
|
|
|
|
|
|
for my $vt (@{$obj->{vt}}) { |
|
|
0
|
|
|
|
|
|
|
|
671
|
0
|
|
|
|
|
|
printf {$OBJ} "vt %f %f %f\n", $vt->{u}, $vt->{v}, $vt->{w}; |
|
|
0
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
} |
|
673
|
0
|
|
|
|
|
|
print {$OBJ} "\n"; |
|
|
0
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
# This is for Poser for now, so no normals. |
|
676
|
|
|
|
|
|
|
# We bailed unless we had UVs, so we assume we have them. |
|
677
|
|
|
|
|
|
|
# There is a slight chance that a model has SOME UVs but not all. |
|
678
|
|
|
|
|
|
|
# Fuck that noise. That's a fucked up improper model, and just rude |
|
679
|
|
|
|
|
|
|
# to do. We're not covering that screwy contingency. |
|
680
|
|
|
|
|
|
|
|
|
681
|
0
|
|
|
|
|
|
my ($r, $g, $m); |
|
682
|
0
|
|
|
|
|
|
for my $f (@{$obj->{f}}) { |
|
|
0
|
|
|
|
|
|
|
|
683
|
0
|
0
|
|
|
|
|
if ($r ne $f->{region}) { |
|
684
|
0
|
|
|
|
|
|
$r = $f->{region}; |
|
685
|
0
|
|
|
|
|
|
print {$OBJ} "# r $r\n"; |
|
|
0
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
} |
|
687
|
0
|
0
|
|
|
|
|
if ($g ne $f->{group}) { |
|
688
|
0
|
|
|
|
|
|
$g = $f->{group}; |
|
689
|
0
|
|
|
|
|
|
print {$OBJ} "g $g\n"; |
|
|
0
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
} |
|
691
|
0
|
0
|
|
|
|
|
if ($m ne $f->{material}) { |
|
692
|
0
|
|
|
|
|
|
$m = $f->{material}; |
|
693
|
0
|
|
|
|
|
|
print {$OBJ} "usemtl $m\n"; |
|
|
0
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
} |
|
695
|
0
|
|
|
|
|
|
my $outpoly = join " ", |
|
696
|
|
|
|
|
|
|
map "$_->{v}->{id}/$_->{vt}->{id}", |
|
697
|
0
|
|
|
|
|
|
@{$f->{verts}}; |
|
698
|
0
|
|
|
|
|
|
print {$OBJ} "f $outpoly\n"; |
|
|
0
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
} |
|
700
|
0
|
0
|
|
|
|
|
close $OBJ unless $was_stdout; |
|
701
|
0
|
|
|
|
|
|
return 1; |
|
702
|
|
|
|
|
|
|
} |
|
703
|
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
1; |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
__END__ |