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__ |