Can't use 'defined(@array)' warning in converting .obj to .h

10,389

Solution 1

defined(@array) used to return whether the array was empty or not. This was a bug.

defined(@array) should always return true (since the number of element in an array is always defined).

Rather than fixing the bug (causing code to silently malfunction), that particular (and useless) use of defined now lets the user know they are doing something wrong and how to fix it.

As the error message suggests, simply use if (@array) to check if the array is empty.

Solution 2

That's because an array doesn't have an 'undefined' state. It just has an 'empty' state.

If you do:

#!/usr/bin/env perl
use strict;
use warnings;

use Data::Dumper;

my @array = undef;   
print Dumper \@array ;

Then what you get is:

$VAR1 = [
          undef
        ];

Which is an array with a single (undefined) element.

But you can test if an array is empty, trivially - because in a scalar context, @array returns a number of elements:

print scalar @list;

As long as you force a scalar context, then you'll get a numeric value out.

Usefully for an 'empty' array, this is zero, and thus works just fine in an 'if' to test if there's values in the array.

if ( @array ) { 
    print "Array has ", scalar @array, " entries\n";
}
else { 
    print "Array is empty.\n";
}

Solution 3

From perldoc:

Use of defined on aggregates (hashes and arrays) is deprecated. It used to report whether memory for that aggregate had ever been allocated. This behavior may disappear in future versions of Perl. You should instead use a simple test for size:

    if (@an_array) { print "has array elements\n" }
    if (%a_hash)   { print "has hash members\n"   }

Solution 4

Just replace

`if(defined(@center)) {
        $xcen = $center[0];
        $ycen = $center[1];
        $zcen = $center[2];
    }`

to

if ( @center ) { 
    print "Array has ", scalar @array, " entries\n";
    $xcen = $center[0];
    $ycen = $center[1];
    $zcen = $center[2];
}
Share:
10,389
tbp
Author by

tbp

Updated on June 04, 2022

Comments

  • tbp
    tbp almost 2 years

    I'm trying to convert my .obj file to a .h header file, but i'm getting "Can't use 'defined(@array)' (Maybe you should just omit the defined()?)" warning and no .h files has created.

    I've tried replacing @center to $center or omintting defined() but it creates .exe file!
    I've read somewhere that it may be a perl version problem, mine is 5.22 and I couldn't find higher versions to try.

    Update1:
    I've put the "obj2opengl.pl " and "myobject.obj" in the same folder. and trying to convert it with this code in console(win10): c:\obj2openglfolder>obj2opengl.pl myobject.obj

    Update2:
    This is the line154 code that cause the problem:

    if(defined(@center)) {
        $xcen = $center[0];
        $ycen = $center[1];
        $zcen = $center[2];
    }
    

    Update3:
    this is the whole code:

    # -----------------------------------------------------------------
    
    # 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;
    
    }
    
  • Sobrique
    Sobrique about 7 years
    This is correct. I am, however, wondering the purpose of the 'defined' test in the above code. I mean, does it test if the array exists or whether it has values? defined implies the former, but the code would do the latter.
  • tbp
    tbp about 7 years
    I've tried this one, this this case the warning goes over but still no .h files created. it just create a .exe file and I dont need it. Thanks anyway
  • tbp
    tbp about 7 years
    Thanks. So what should I do exactly?I'm not familiar to perl
  • Sobrique
    Sobrique about 7 years
    Hire a perl programmer maybe? I mean, you've given us 4 lines of perl to look at, and we can tell you what's wrong with it - but we can't tell you how to fix it, because we can't tell what the rest of your code is doing.