The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

use strict;
use Time::HiRes qw(sleep);
use OpenGL ':old', ':glutfunctions', ':glutconstants';

my $where = (@ARGV ? 'far away' : 'near Earth');
print "Camera position: $where.\n";
print "Give arguments to position camera far away.\n";

my $field_of_view = (@ARGV ? 20 : 100); # Degrees
my $minviewdist = 0.1;
my $maxviewdist = 1000;

my $mercury = 0;
my $venus = 0;
my $earth = 0;
my $earthMoon = 0;
my $earthspin = 0;
my $mars = 0;
my $jupiter = 230;		# Make them visible
my $jups1 = 0;
my $jups2 = 0;
my $jups3 = 0;
my $jups4 = 0;
my $saturn = 250;		# Make them visible

sub resizeHandler {		# Not auto yet
  my ($wind_w, $wind_h) = @_;
  
  glMatrixMode( GL_PROJECTION );
   glLoadIdentity();
   gluPerspective( $field_of_view, $wind_w/$wind_h,
		   $minviewdist, $maxviewdist );
  glMatrixMode( GL_MODELVIEW );
}

sub display {
  # clear the canvas
  glClearColor(0,0,0,1);
  glDrawBuffer(GL_FRONT_AND_BACK);
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  glDrawBuffer(GL_BACK);

  glLoadIdentity();

  if (@ARGV) {
    # move the squares back a bit
    glTranslatef( 0, 0, -500 );
    # and add a tilt
    glRotatef(-70, 1,0,0);
  } else {
    # place viewpoint on the surface of the planet
    glRotatef(30, 1,0,0);
    glTranslatef( 0, -5, 2 );
    glRotatef(-$earthspin, 0,1,0);
    glTranslatef( 0, 0, -60 );
    glRotatef(-90, 1,0,0);
    glRotatef(90-$earth, 0,0,1);
  }

  # Sun light
  glLightfv(GL_LIGHT0, GL_POSITION, pack "f4", 0, 0, 0, 1);
  #glLightfv(GL_LIGHT1, GL_DIFFUSE,  pack "f4", 1, 1, 1, 1);
  #glLightfv(GL_LIGHT0, GL_DIFFUSE,  pack "f4", 0, 0, 0, 1);
  # Same for specular?

  # Moon light

  glPushMatrix();

  # Position the moon
  glRotatef($earth,0,0,1);
  glTranslatef( -60, 0, 0 );
  glRotatef($earthMoon,0,0,1);
  glTranslatef( -10, 0, 0 );
  glLightfv(GL_LIGHT1, GL_POSITION, pack "f4", 0, 0, 0, 1);
  my $moon_bright = 0.1*(1 + cos($earthMoon*3.1415926/180));
  glLightfv(GL_LIGHT1, GL_AMBIENT, 
	    pack "f4", $moon_bright, $moon_bright, $moon_bright, 1);
  
  glPopMatrix();

  # Sun
  # glColor3f(1,1,1);
  glMaterialfv( GL_FRONT, GL_EMISSION, pack 'f4', 1, 1, 0, 1);
  glutSolidSphere(20,10,10);
  glMaterialfv( GL_FRONT, GL_EMISSION, pack 'f4', 0, 0, 0, 1);
  
  glPushMatrix();

  # Position the mercury
  glRotatef($mercury,0,0,1);
  glTranslatef( -30, 0, 0 );
  glColor3f(0.6, 0.6, 0.6);
  glutSolidSphere(2,10,10);
  
  glPopMatrix();
  
  glPushMatrix();

  # Position the venus
  glRotatef($venus,0,0,1);
  glTranslatef( -40, 0, 0 );
  glColor3f(0,1,0);
  glutSolidSphere(5,10,10);
  
  glPopMatrix();
  
  glPushMatrix();

  # Position the earth
  glRotatef($earth,0,0,1);
  glTranslatef( -60, 0, 0 );
  glColor3f(0,0,1);

  glPushMatrix();

  # Rotate the planet earth
  glRotatef($earthspin,0,0,1);
  
  glEnable( GL_LIGHT1 );
  glutSolidSphere(5,10,10);
  glDisable( GL_LIGHT1 );

  glPopMatrix();

  
  # Position the earth's moon
  glRotatef($earthMoon,0,0,1);
  glTranslatef( -10, 0, 0 );
  glColor3f(0.5,0.5,0.5);
  glutSolidSphere(1,10,10);

  glPopMatrix();
  
  glPushMatrix();

  # Position the mars
  glRotatef($mars,0,0,1);
  glTranslatef( -80, 0, 0 );
  glColor3f(1,0,0);
  glutSolidSphere(4,10,10);
  
  glPopMatrix();
  
  glPushMatrix();

  # Position the jupiter
  glRotatef($jupiter,0,0,1);
  glTranslatef( -120, 0, 0 );
  glColor3f(0.6,0.6,0.6);
  glutSolidSphere(9,10,10);

  glPushMatrix();

  # Position the jup's moon1
  glRotatef($jups1,0,0,1);
  glTranslatef( -6, 0, 0 );
  glColor3f(0.5,0.5,0.5);
  glutSolidSphere(1,10,10);
  
  glPopMatrix();
  
  glPushMatrix();

  # Position the jup's moon2
  glRotatef($jups2,0,0,1);
  glTranslatef( -8, 0, 0 );
  glColor3f(0.5,0.5,0.5);
  glutSolidSphere(1,10,10);
  
  glPopMatrix();
  
  glPushMatrix();

  # Position the jup's moon3
  glRotatef($jups3,0,0,1);
  glTranslatef( -10, 0, 0 );
  glColor3f(0.5,0.5,0.5);
  glutSolidSphere(1,10,10);
  
  glPopMatrix();
  
  glPushMatrix();

  # Position the jup's moon4
  glRotatef($jups4,0,0,1);
  glTranslatef( -12, 0, 0 );
  glColor3f(0.5,0.5,0.5);
  glutSolidSphere(1,10,10);
  
  glPopMatrix();
  
  glPopMatrix();
  
  glPushMatrix();

  # Position the saturn
  glRotatef($saturn,0,0,1);
  glTranslatef( -150, 0, 0 );
  glColor3f(0.5,0.5,0.5);
  glutSolidSphere(8,10,10);

  glRotatef(-$saturn,0,0,1);
  glRotatef(14, 0.707, -0.707, 0); # What is the actual tilt?
  glScalef(1,1,0.2);		# Giving smaller values makes it white?!
  eval {glutSolidTorus(4.5,13,10,10)};
  
  glPopMatrix();
  
  glPopMatrix();
  
  glutSwapBuffers();
}

glutInit();
glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH );
glutCreateWindow('Planets Example');
glutDisplayFunc(\&display);
glutReshapeFunc(\&resizeHandler);

#glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glEnable( GL_DEPTH_TEST );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glEnable( GL_COLOR_MATERIAL );
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, pack 'f4', 0.1, 0.1, 0.1, 1);


while ( sleep(0.1) ) {
  glutMainLoopEvent();
  $mercury += 1/0.24;
  $mercury -= 360 if $mercury >= 360;
  
  $venus += 1/0.62;
  $venus -= 360 if $venus >= 360;
  
  $earthMoon += 12.36;		# Relative to sun-earth line
  $earthMoon -= 360 if $earthMoon >= 360;
  
  $earthspin += 3.65;		# 1/100 of real
  $earthspin -= 360 if $earthspin >= 360;
  
  $earth += 1;
  $earth -= 360 if $earth >= 360;
  
  $venus += 1/0.62;
  $venus -= 360 if $venus >= 360;
  
  $mars += 1/1.88;			# Wrong
  $mars -= 360 if $mars >= 360;
  
  $jupiter += 1/11.86;
  $jupiter -= 360 if $jupiter >= 360;
  
  $jups1 += -1/11.86 + 365.2/1.77;
  $jups1 -= 360 if $jups1 >= 360;
  
  $jups2 += -1/11.86 + 365.2/3.55;
  $jups2 -= 360 if $jups2 >= 360;
  
  $jups3 += -1/11.86 + 365.2/7.16;
  $jups3 -= 360 if $jups3 >= 360;
  
  $jups4 += -1/11.86 + 365.2/16.69;
  $jups4 -= 360 if $jups4 >= 360;
  
  $saturn += 1/29.46;
  $saturn -= 360 if $saturn >= 360;
  
  glutPostRedisplay();
}