5.2. Using VOS in Perl

With the help of the Simple Wrapper and Interface Generator (SWIG) we have created bindings so that you can access most of the VOS C++ API from the comfort of Perl. The API is similar enough that one should be able to get by using just the C++ API documentation and a little hacking!

5.2.1. A Complete VOS Virtual World Server in Perl

This section presents a virtual world built using the Abstract 3D Layer (A3DL) in Perl. (This world, the Conic Temple, was inspired by one of our very first test worlds for an ancient VOS/3D prototype). This code can also be found in the source distribution as swig/perl/apps/conic.pl


#!/usr/bin/perl

#
# Conic.pl       Conic Temple      A Sample VOS World
#
# Copyright 2003 Peter Amstutz
#
# Permission is granted to use any part of the following Perl program,
# with or without modification, in your own programs without
# restriction.

# Import the VOS library.
use VOS;

# We need to tell the C++ system which
# extensions we're planning to use
VOS::Property::registerExtenders();
VOS::Sector::registerExtenders();
VOS::Object3D::registerExtenders();
VOS::Cube::registerExtenders();
VOS::Cylinder::registerExtenders();
VOS::Cone::registerExtenders();
VOS::Light::registerExtenders();
VOS::PolygonMesh::registerExtenders();
VOS::Viewpoint::registerExtenders();
VOS::Search::registerExtenders();
VOS::Material::registerExtenders();

# Now create a local site.  This will do all
# our object management and handle network
# communication
my $site = VOSc::new_LocalSocketSite_a(VOS::NoAccessControl_static());
VOS::LocalSite::extendMetaObject($site, "misc:search");

# Tell the site we want it to sleep when it doesn't
# have anything else to do
$site->setTimeoutOnSelect(-1);

# Create the world object!
# Note that we need to explicitly cast
# it to get the Sector API
$w = VOS::castToSector($site->createMetaObject("world", ["a3dl:sector"]));

# Create the light and position it in the world.  This should
# be pretty straightforward.  Note that you need to set an
# access control policy (in this case "no" access control, that is
# to say, no restrictions) or else the system will by default
# deny all remote access to an object for security reasons.
my $light = VOS::castToLight($site->createMetaObject("light", ["a3dl:light"]));
$light->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$light->setPosition(0, 5, -4);
$light->setRadius(60);
$light->setColor(.4, .4, .4);

# Now add the light to the world.
$w->insertChild(-1, "testlight", $light);


# another light
my $light = VOS::castToLight($site->createMetaObject("light", ["a3dl:light"]));
$light->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$light->setPosition(0, 3, -20);
$light->setRadius(30);
$light->setColor(.4, .4, .4);

$w->insertChild(-1, "anotherlight", $light);

# A mesh is a set of polygons whose corners are specified by verticies.
# This allows you to specify raw geometry in VOS.
my $ps = VOS::castToPolygonMesh($site->createMetaObject("outerwalls", ["a3dl:object3D.polygonmesh", "a3dl:static"]));
$ps->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());

$ps->setVertices([[-20, -1.2, -20], [-20, -1.2, 20], [-20, 2.9, -20], [-20, 2.9, 20],
				  [20, -1.2, -20], [20, -1.2, 20], [20, 4.9, -20], [20, 4.9, 20]]);

@verts = $ps->getVertices();

for($i = 0; $i < (scalar @verts); $i++) {
  print "$i: $verts[$i][0] $verts[$i][1] $verts[$i][2]\n";
}

# The second parameter is the polygon color, as a hex triple,
# the third parameter is texture scaling (unused for solid colors)
# the final parameters are the vertices specifying the polygon
$ps->setPolygons([[3, 2, 6, 7], [2, 3, 1, 0], [6, 4, 5, 7],
				  [3, 7, 5, 1], [2, 0, 4, 6], [0, 1, 5, 4]]);

@polys = $ps->getPolygons();

for($i = 0; $i < (scalar @polys); $i++) {
  $p = $polys[$i];
  print "$polys[$i][$i2] ";
  for($i2 = 0; $i2 < (scalar @$p); $i2++) {
	print "$polys[$i][$i2] ";
  }
  print "\n";
}

$ps->setOrientation(0, 1, 0, 0);
$ps->setPosition(0, 0, 0);

# now add these walls (well, actually just a big black box) to the world
$w->insertChild(-1, "outerwalls", $ps);

# The foundation is just a container object, it doesn't look like
# anything on its own
$foundation = VOS::castToObject3D($site->createMetaObject("foundation", ["a3dl:object3D"]));
$foundation->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$foundation->setPosition(0, 0, 0);
$foundation->setOrientation(0, 1, 0, 0);

# Now the base (the big flat thing)
$base = VOS::castToCube($site->createMetaObject("base", ["a3dl:object3D.cube"]));
$base->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$base->setScalingHT(10, .2, 18.1);
$base->setPosition(0, 1, -10);
$base->setOrientation(0, 1, 0, 0);
$basematerial = VOS::castToMaterial($site->createMetaObject("brown", ["a3dl:material"]));
$basematerial->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$basematerial->setColor(VOS::Material::hexStringToFloats("#B3802A"));
$base->setMaterial($basematerial);

$foundation->insertChild(-1, "base", $base);
$w->insertChild(-1, "foundation", $foundation);

$columncolor = VOS::castToMaterial($site->createMetaObject("columncolor", ["a3dl:material"]));
$columncolor->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$columncolor->setColor(VOS::Material::hexStringToFloats("#CCCCCC"));

# We're going to create two a rows of columns, so first
# define subroutine to create a single column
sub createColumn {
  my ($x, $y, $z) = @_;

# A column consists of a cylinder and a flat thingy on top
  $column = VOS::castToCylinder($site->createMetaObject("column$x$y$z", ["a3dl:object3D.cylinder"]));
  $column->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
  $column->setScalingHT(.2, 2, .2);
  $column->setPosition($x, $y, $z);
  $column->setMaterial($columncolor);
  $column->setOrientation(0, 1, 0, 0);

  $columntop = VOS::castToCube($site->createMetaObject("columntop$x$y$z", ["a3dl:object3D.cube"]));
  $columntop->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
  $columntop->setScalingHT(.22, .03, .22);
  $columntop->setPosition(0, 1, 0);
  $columntop->setOrientation(0, 1, 0, 0);
  $columntop->setMaterial($columncolor);

  $column->insertChild(-1, "columntop", $columntop);
  $foundation->insertChild(-1, "column", $column);
}

# create two parallel lines of columns
for($i = -4; $i >= -16; $i -= 2) {
  createColumn(-2, 2, $i);
  createColumn(2, 2, $i);
}

# the dais at the far end
$platform = VOS::castToCube($site->createMetaObject("platform", ["a3dl:object3D.cube"]));
$platform->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$platform->setScalingHT(8, .3, 2.5);
$platform->setPosition(0, 1.2, -2.3);
$platform->setOrientation(0, 1, 0, 0);
$platform->setMaterial($columncolor);

$foundation->insertChild(-1, "platform", $platform);

# the altar
$altar = VOS::castToCube($site->createMetaObject("altar", ["a3dl:object3D.cube"]));
$altar->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$altar->setScalingHT(2.2, 1, 1.7);
$altar->setPosition(0, .5, 0);
$altar->setOrientation(0, 1, 0, 0);
$altar->setMaterial($columncolor);

$platform->insertChild(-1, "altar", $altar);

# the most holy cones... :-)
$cone = VOS::castToCone($site->createMetaObject("cone1", ["a3dl:object3D.cone"]));
$cone->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$cone->setScalingHT(2.4, 3, 2.4);
$cone->setPosition(-2.8, 1.5, 0);
$cone->setOrientation(0, 1, 0, 0);
$cone->setMaterial($columncolor);

$platform->insertChild(-1, "cone", $cone);

$cone = VOS::castToCone($site->createMetaObject("cone2", ["a3dl:object3D.cone"]));
$cone->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$cone->setScalingHT(2.4, 3, 2.4);
$cone->setPosition(2.8, 1.5, 0);
$cone->setOrientation(0, 1, 0, 0);
$cone->setMaterial($columncolor);

$platform->insertChild(-1, "cone", $cone);

$red = VOS::castToMaterial($site->createMetaObject("red", ["a3dl:material"]));
$red->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$red->setColor(VOS::Material::hexStringToFloats("#FF0000"));

# the bright red carpet!
$carpet = VOS::castToCube($site->createMetaObject("carpet", ["a3dl:object3D.cube"]));
$carpet->setPropertyAccessControl(VOS::NoPropertyAccessControl_static());
$carpet->setScalingHT(3.5, .2, 16);
$carpet->setPosition(0, 1.05, -11);
$carpet->setOrientation(0, 1, 0, 0);
$carpet->setMaterial($red);

$foundation->insertChild(-1, "carpet", $carpet);

# Set up a starting point for users
$vp = VOS::castToViewpoint($site->createMetaObject("default-viewpoint", ["a3dl:viewpoint"]));
$vp->initialize();
$vp->setPosition(0, 2, -20);
$vp->setOrientation(0, 1, 0, 0);

$w->insertChild(-1, "default-viewpoint", $vp);

# Set up a starting point for users
$vp = VOS::castToViewpoint($site->createMetaObject("webcam-viewpoint", ["a3dl:viewpoint"]));
$vp->initialize();
$vp->setPosition(-2.195347, 5.173016, 1.916739);
$vp->setOrientation(0.022262, 0.990621, -0.134815, 161.403654);

$w->insertChild(-1, "webcam-viewpoint", $vp);

# Inform the user as to what the site name is!
print "Running world ".$w->getURL()->getString()."\n";

# Okay, the world is created, now go into a infinite loop
# serving the world to whoever connects.
while(1) { $site->flushIncomingBuffers(); }