我正在尝试将我的.obj文件转换为.h头文件,但我得到“无法使用”定义(@array)'(也许你应该省略已定义的()?)“警告并没有创建.h文件。
我已尝试将@center
替换为$center
或省略defined()
,但会创建.exe文件!
我在某处看过它可能是一个perl版本的问题,我的是5.22,我找不到更高版本的尝试。
UPDATE1:
我把“obj2opengl.pl”和“myobject.obj”放在同一个文件夹中。并尝试在控制台(win10)中使用此代码转换它:
c:\obj2openglfolder>obj2opengl.pl myobject.obj
UPDATE2:
这是导致问题的line154代码:
if(defined(@center)) {
$xcen = $center[0];
$ycen = $center[1];
$zcen = $center[2];
}
UPDATE3:
这是整个代码:
# -----------------------------------------------------------------
# Main Program
# -----------------------------------------------------------------
handleArguments();
# derive center coords and scale factor if neither provided nor disabled
unless(defined($scalefac) && defined($xcen)) {
calcSizeAndCenter();
}
if($verbose) {
printInputAndOptions();
}
# TODO check integrity: Does every referenced vertex, normal and coord
exist?
loadData();
normalizeNormals();
if($verbose) {
printStatistics();
}
writeOutput();
# -----------------------------------------------------------------
# Sub Routines
# -----------------------------------------------------------------
sub handleArguments() {
my $help = 0;
my $man = 0;
my $noscale = 0;
my $nomove = 0;
$verbose = 1;
$errorInOptions = !GetOptions (
"help" => \$help,
"man" => \$man,
"noScale" => \$noscale,
"scale=f" => \$scalefac,
"noMove" => \$nomove,
"center=f{3}" => \@center,
"outputFilename=s" => \$outFilename,
"nameOfObject=s" => \$object,
"verbose!" => \$verbose,
);
if($noscale) {
$scalefac = 1;
}
if($nomove) {
@center = (0, 0, 0);
}
if(@center) {
$xcen = $center[0];
$ycen = $center[1];
$zcen = $center[2];
}
if($#ARGV == 0) {
my ($file, $dir, $ext) = fileparse($ARGV[0], qr/\.[^.]*/);
$inFilename = $dir . $file . $ext;
} else {
$errorInOptions = true;
}
# (optional) derive output filename from input filename
unless($errorInOptions || defined($outFilename)) {
my ($file, $dir, $ext) = fileparse($inFilename, qr/\.[^.]*/);
$outFilename = $dir . $file . ".h";
}
# (optional) define object name from output filename
unless($errorInOptions || defined($object)) {
my ($file, $dir, $ext) = fileparse($outFilename, qr/\.[^.]*/);
$object = $file;
}
($inFilename ne $outFilename) or
die ("Input filename must not be the same as output filename")
unless($errorInOptions);
if($errorInOptions || $man || $help) {
pod2usage(-verbose => 2) if $man;
pod2usage(-verbose => 1) if $help;
pod2usage();
}
# check wheter file exists
open ( INFILE, "<$inFilename" )
|| die "Can't find file '$inFilename' ...exiting \n";
close(INFILE);
}
# Stores center of object in $xcen, $ycen, $zcen
# and calculates scaling factor $scalefac to limit max
# side of object to 1.0 units
sub calcSizeAndCenter() {
open ( INFILE, "<$inFilename" )
|| die "Can't find file $inFilename...exiting \n";
$numVerts = 0;
my (
$xsum, $ysum, $zsum,
$xmin, $ymin, $zmin,
$xmax, $ymax, $zmax,
);
while ( $line = <INFILE> )
{
chop $line;
if ($line =~ /v\s+.*/)
{
$numVerts++;
@tokens = split(' ', $line);
$xsum += $tokens[1];
$ysum += $tokens[2];
$zsum += $tokens[3];
if ( $numVerts == 1 )
{
$xmin = $tokens[1];
$xmax = $tokens[1];
$ymin = $tokens[2];
$ymax = $tokens[2];
$zmin = $tokens[3];
$zmax = $tokens[3];
}
else
{
if ($tokens[1] < $xmin)
{
$xmin = $tokens[1];
}
elsif ($tokens[1] > $xmax)
{
$xmax = $tokens[1];
}
if ($tokens[2] < $ymin)
{
$ymin = $tokens[2];
}
elsif ($tokens[2] > $ymax)
{
$ymax = $tokens[2];
}
if ($tokens[3] < $zmin)
{
$zmin = $tokens[3];
}
elsif ($tokens[3] > $zmax)
{
$zmax = $tokens[3];
}
}
}
}
close INFILE;
# Calculate the center
unless(defined($xcen)) {
$xcen = $xsum / $numVerts;
$ycen = $ysum / $numVerts;
$zcen = $zsum / $numVerts;
}
# Calculate the scale factor
unless(defined($scalefac)) {
my $xdiff = ($xmax - $xmin);
my $ydiff = ($ymax - $ymin);
my $zdiff = ($zmax - $zmin);
if ( ( $xdiff >= $ydiff ) && ( $xdiff >= $zdiff ) )
{
$scalefac = $xdiff;
}
elsif ( ( $ydiff >= $xdiff ) && ( $ydiff >= $zdiff ) )
{
$scalefac = $ydiff;
}
else
{
$scalefac = $zdiff;
}
$scalefac = 1.0 / $scalefac;
}
}
sub printInputAndOptions() {
print "Input file : $inFilename\n";
print "Output file : $outFilename\n";
print "Object name : $object\n";
print "Center : <$xcen, $ycen, $zcen>\n";
print "Scale by : $scalefac\n";
}
sub printStatistics() {
print "----------------\n";
print "Vertices : $numVerts\n";
print "Faces : $numFaces\n";
print "Texture Coords : $numTexture\n";
print "Normals : $numNormals\n";
}
# reads vertices into $xcoords[], $ycoords[], $zcoords[]
# where coordinates are moved and scaled according to
# $xcen, $ycen, $zcen and $scalefac
# reads texture coords into $tx[], $ty[]
# where y coordinate is mirrowed
# reads normals into $nx[], $ny[], $nz[]
# but does not normalize, see normalizeNormals()
# reads faces and establishes lookup data where
# va_idx[], vb_idx[], vc_idx[] for vertices
# ta_idx[], tb_idx[], tc_idx[] for texture coords
# na_idx[], nb_idx[], nc_idx[] for normals
# store indizes for the former arrays respectively
# also, $face_line[] store actual face string
sub loadData {
$numVerts = 0;
$numFaces = 0;
$numTexture = 0;
$numNormals = 0;
open ( INFILE, "<$inFilename" )
|| die "Can't find file $inFilename...exiting \n";
while ($line = <INFILE>)
{
chop $line;
# vertices
if ($line =~ /v\s+.*/)
{
@tokens= split(' ', $line);
$x = ( $tokens[1] - $xcen ) * $scalefac;
$y = ( $tokens[2] - $ycen ) * $scalefac;
$z = ( $tokens[3] - $zcen ) * $scalefac;
$xcoords[$numVerts] = $x;
$ycoords[$numVerts] = $y;
$zcoords[$numVerts] = $z;
$numVerts++;
}
# texture coords
if ($line =~ /vt\s+.*/)
{
@tokens= split(' ', $line);
$x = $tokens[1];
$y = 1 - $tokens[2];
$tx[$numTexture] = $x;
$ty[$numTexture] = $y;
$numTexture++;
}
#normals
if ($line =~ /vn\s+.*/)
{
@tokens= split(' ', $line);
$x = $tokens[1];
$y = $tokens[2];
$z = $tokens[3];
$nx[$numNormals] = $x;
$ny[$numNormals] = $y;
$nz[$numNormals] = $z;
$numNormals++;
}
# faces
if ($line =~ /f\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)(\s+([^ ]+))?/)
{
@a = split('/', $1);
@b = split('/', $2);
@c = split('/', $3);
$va_idx[$numFaces] = $a[0]-1;
$ta_idx[$numFaces] = $a[1]-1;
$na_idx[$numFaces] = $a[2]-1;
$vb_idx[$numFaces] = $b[0]-1;
$tb_idx[$numFaces] = $b[1]-1;
$nb_idx[$numFaces] = $b[2]-1;
$vc_idx[$numFaces] = $c[0]-1;
$tc_idx[$numFaces] = $c[1]-1;
$nc_idx[$numFaces] = $c[2]-1;
$face_line[$numFaces] = $line;
$numFaces++;
# ractangle => second triangle
if($5 != "")
{
@d = split('/', $5);
$va_idx[$numFaces] = $a[0]-1;
$ta_idx[$numFaces] = $a[1]-1;
$na_idx[$numFaces] = $a[2]-1;
$vb_idx[$numFaces] = $d[0]-1;
$tb_idx[$numFaces] = $d[1]-1;
$nb_idx[$numFaces] = $d[2]-1;
$vc_idx[$numFaces] = $c[0]-1;
$tc_idx[$numFaces] = $c[1]-1;
$nc_idx[$numFaces] = $c[2]-1;
$face_line[$numFaces] = $line;
$numFaces++;
}
}
}
close INFILE;
}
sub normalizeNormals {
for ( $j = 0; $j < $numNormals; ++$j)
{
$d = sqrt ( $nx[$j]*$nx[$j] + $ny[$j]*$ny[$j] + $nz[$j]*$nz[$j] );
if ( $d == 0 )
{
$nx[$j] = 1;
$ny[$j] = 0;
$nz[$j] = 0;
}
else
{
$nx[$j] = $nx[$j] / $d;
$ny[$j] = $ny[$j] / $d;
$nz[$j] = $nz[$j] / $d;
}
}
}
sub fixedIndex {
local $idx = $_[0];
local $num = $_[1];
if($idx >= 0)
{
$idx;
} else {
$num + $idx + 1;
}
}
sub writeOutput {
open ( OUTFILE, ">$outFilename" )
|| die "Can't create file $outFilename ... exiting\n";
print OUTFILE "/*\n";
print OUTFILE "created with obj2opengl.pl\n\n";
# some statistics
print OUTFILE "source file : $inFilename\n";
print OUTFILE "vertices : $numVerts\n";
print OUTFILE "faces : $numFaces\n";
print OUTFILE "normals : $numNormals\n";
print OUTFILE "texture coords : $numTexture\n";
print OUTFILE "\n\n";
# example usage
print OUTFILE "// include generated arrays\n";
print OUTFILE "#import \"".$outFilename."\"\n";
print OUTFILE "\n";
print OUTFILE "// set input data to arrays\n";
print OUTFILE "glVertexPointer(3, GL_FLOAT, 0, ".$object."Verts);\n";
print OUTFILE "glNormalPointer(GL_FLOAT, 0, ".$object."Normals);\n"
if $numNormals > 0;
print OUTFILE "glTexCoordPointer(2, GL_FLOAT, 0, ".$object."TexCoords);\n"
if $numTexture > 0;
print OUTFILE "\n";
print OUTFILE "// draw data\n";
print OUTFILE "glDrawArrays(GL_TRIANGLES, 0, ".$object."NumVerts);\n";
print OUTFILE "*/\n\n";
# needed constant for glDrawArrays
print OUTFILE "unsigned int ".$object."NumVerts = ".($numFaces * 3).";\n\n";
# write verts
print OUTFILE "float ".$object."Verts \[\] = {\n";
for( $j = 0; $j < $numFaces; $j++)
{
$ia = fixedIndex($va_idx[$j], $numVerts);
$ib = fixedIndex($vb_idx[$j], $numVerts);
$ic = fixedIndex($vc_idx[$j], $numVerts);
print OUTFILE " // $face_line[$j]\n";
print OUTFILE " $xcoords[$ia], $ycoords[$ia], $zcoords[$ia],\n";
print OUTFILE " $xcoords[$ib], $ycoords[$ib], $zcoords[$ib],\n";
print OUTFILE " $xcoords[$ic], $ycoords[$ic], $zcoords[$ic],\n";
}
print OUTFILE "};\n\n";
# write normals
if($numNormals > 0) {
print OUTFILE "float ".$object."Normals \[\] = {\n";
for( $j = 0; $j < $numFaces; $j++) {
$ia = fixedIndex($na_idx[$j], $numNormals);
$ib = fixedIndex($nb_idx[$j], $numNormals);
$ic = fixedIndex($nc_idx[$j], $numNormals);
print OUTFILE " // $face_line[$j]\n";
print OUTFILE " $nx[$ia], $ny[$ia], $nz[$ia],\n";
print OUTFILE " $nx[$ib], $ny[$ib], $nz[$ib],\n";
print OUTFILE " $nx[$ic], $ny[$ic], $nz[$ic],\n";
}
print OUTFILE "};\n\n";
}
# write texture coords
if($numTexture) {
print OUTFILE "float ".$object."TexCoords \[\] = {\n";
for( $j = 0; $j < $numFaces; $j++) {
$ia = fixedIndex($ta_idx[$j], $numTexture);
$ib = fixedIndex($tb_idx[$j], $numTexture);
$ic = fixedIndex($tc_idx[$j], $numTexture);
print OUTFILE " // $face_line[$j]\n";
print OUTFILE " $tx[$ia], $ty[$ia],\n";
print OUTFILE " $tx[$ib], $ty[$ib],\n";
print OUTFILE " $tx[$ic], $ty[$ic],\n";
}
print OUTFILE "};\n\n";
}
close OUTFILE;
}
答案 0 :(得分:5)
那是因为数组没有'undefined'状态。它只是一个'空'状态。
如果你这样做:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my @array = undef;
print Dumper \@array ;
然后你得到的是:
$VAR1 = [
undef
];
这是一个包含单个(未定义)元素的数组。
但是你可以测试一个数组是否为空,非常简单 - 因为在标量上下文中,@array
返回了许多元素:
print scalar @list;
只要强制使用标量上下文,就会得到一个数值。
对于'空'数组有用,这是零,因此在'if'中可以正常工作,以测试数组中是否有值。
if ( @array ) {
print "Array has ", scalar @array, " entries\n";
}
else {
print "Array is empty.\n";
}
答案 1 :(得分:4)
defined(@array)
用于返回数组是否为空。这是一个错误。
defined(@array)
应始终返回true(因为始终定义数组中的元素数)。
而不是修复错误(导致代码无声地出现故障),defined
的特定(和无用)使用现在让用户知道他们做错了什么以及如何修复它。
如错误消息所示,只需使用if (@array)
检查数组是否为空。
答案 2 :(得分:1)
来自perldoc:
不推荐在聚合(哈希和数组)上使用已定义的内容。它曾用于报告是否已分配该聚合的内存。在将来的Perl版本中,此行为可能会消失。您应该使用简单的大小测试:
if (@an_array) { print "has array elements\n" }
if (%a_hash) { print "has hash members\n" }
答案 3 :(得分:0)
只需替换
`if(defined(@center)) {
$xcen = $center[0];
$ycen = $center[1];
$zcen = $center[2];
}`
到
if ( @center ) {
print "Array has ", scalar @array, " entries\n";
$xcen = $center[0];
$ycen = $center[1];
$zcen = $center[2];
}