<?php

    
/*
        Converted example from http://astronomy.swin.edu.au/pbourke/historical/glut/

        Original Author Paul Bourke <pbourke@swin.edu.au>

        Converted to PHP by Markus Fischer <mfischer@guru.josefine.at>
    */

    
error_reporting(E_ALL);

    
define('DRAFT',        0);
    
define('MEDIUM',    1);
    
define('BEST',        2);

    
$drawquality DRAFT;
    
$spincamera TRUE;
    
$cameradirection 1;
    
$updownrotate 60.0;
    
$ballbounce TRUE;
    
$ballspeed 2.0;

    foreach(array(
'OVALID''SPHEREID''BOXID''PLANEID''TEXTID') as $i => $const)
        
define($const$i+1);

    for (
$i=1;$i<$argc;$i++) {
        if (
strstr($argv[$i],"-h") != NULL
            
GiveUsage($argv[0]);
        if (
strstr($argv[$i],"-q") != NULL) {
            if (
$i+>= $argc)
                
GiveUsage($argv[0]);
            
$drawquality $argv[$i+1];
            if (
$drawquality DRAFT)
                
$drawquality DRAFT;
            if (
$drawquality BEST)
                
$drawquality BEST;
            
$i++;
        }
    }

   
/* Set things up and go */
   
glutInit($argv);
   
glutInitDisplayMode(GLUT_DOUBLE GLUT_RGB GLUT_DEPTH);
   
glutCreateWindow("OpenGL Demo");
   
glutDisplayFunc('Display');
   
glutVisibilityFunc('HandleVisibility');
   
glutKeyboardFunc('HandleKeyboard');
   
glutSpecialFunc('HandleSpecialKeyboard');
   
glutMouseFunc('HandleMouse');
   
CreateEnvironment();

   
/* Set up some menus */
   
$speedmenu glutCreateMenu('HandleSpeedMenu');
   
glutAddMenuEntry("Slow",1);
   
glutAddMenuEntry("Medium",2);
   
glutAddMenuEntry("fast",3);
   
$mainmenu glutCreateMenu('HandleMainMenu');
   
glutAddMenuEntry("Toggle camera spin",1);
   
glutAddMenuEntry("Toggle ball bounce",2);
   
glutAddSubMenu("Ball speed",$speedmenu);
   
glutAddMenuEntry("Quit",100);
   
glutAttachMenu(GLUT_RIGHT_BUTTON);

   
glutMainLoop();
   exit;

    
/*
       This is where global settings are made, that is, 
       things that will not change in time 
    */
    
function CreateEnvironment() {
        global 
$drawquality;

        
glEnable(GL_DEPTH_TEST);
        if (
$drawquality == DRAFT)
              
glShadeModel(GL_FLAT);
        if (
$drawquality == MEDIUM)
            
glShadeModel(GL_SMOOTH);
        if (
$drawquality == BEST) {
            
glEnable(GL_LINE_SMOOTH);
            
glEnable(GL_POINT_SMOOTH);
            
glEnable(GL_POLYGON_SMOOTH); 
            
glShadeModel(GL_SMOOTH);    
            
glDisable(GL_DITHER);         /* Assume RGBA capabilities */
        
}

        
glLineWidth(1.0);
        
glPointSize(1.0);
        
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
        
glFrontFace(GL_CW);
        
glDisable(GL_CULL_FACE);
        
glClearColor(0.0,0.0,0.0,0.0);         /* Background colour */
        
glEnable(GL_COLOR_MATERIAL);
    }

    
/*
       This is the basic display callback routine
       It creates the geometry, lighting, and viewing position
       In this case it rotates the camera around the scene
    */
    
function Display() {

        
glClear(GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT);

        
glPushMatrix();
        
MakeCamera(FALSE,0,0);
        
MakeLighting();
        
MakeGeometry();
        
glPopMatrix();

        
/* glFlush(); This isn't necessary for double buffers */
        
glutSwapBuffers();
    }

    
/*
        Create the geometry
    */
    
function MakeGeometry() {
        global 
$drawquality$ballbounce$ballspeed;
        static 
$theta 0.0;

        
$radius 0.5;
        
$mshin1 = array(5.0);               /* For the sphere */
        
$mspec1 = array(0.5,0.5,0.5,1.0);
        
$mdiff1 = array(0.6,0.0,0.6,1.0);
        
$mamb1  = array(0.1,0.0,0.1,1.0);
        
$mdiff2 = array(0.0,1.0,0.0,1.0);   /* Green plane */
        
$mamb2  = array(0.0,0.2,0.0,1.0);
        
$mdiff3 = array(0.5,0.5,0.5,1.0);  /* Grey boxes */
        
$mamb3  = array(0.2,0.2,0.2,1.0);

        
/* Create a green ground plane */
        
glLoadName(PLANEID);
        if (
$drawquality DRAFT)
            
glBegin(GL_POLYGON);
        else
            
glBegin(GL_LINE_LOOP);
        
glColor3f(0.0,1.0,0.0);
        if (
$drawquality DRAFT) {
            
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE$mdiff2);
            
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT$mamb2);
        }
        
glNormal3f0.01.00.0);
        
glVertex3f2.00.02.0);
        
glVertex3f2.00.0,-2.0);
        
glVertex3f(-2.00.0,-2.0);
        
glVertex3f(-2.00.02.0); 
        
glEnd();

        
/* Place a few grey boxes around the place */
        
glLoadName(BOXID);
        
glColor3f(0.5,0.5,0.5);
        if (
$drawquality DRAFT) {
            
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE$mdiff3);
            
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT$mamb3);
        }
        
glPushMatrix();
        
glTranslatef(1.8,0.2,1.8);
        if (
$drawquality DRAFT)
            
glutSolidCube(0.4);
        else
            
glutWireCube(0.4);
        
glTranslatef(-3.6,0.0,0.0);
        if (
$drawquality DRAFT)
            
glutSolidCube(0.4);
        else
            
glutWireCube(0.4);
        
glPopMatrix();

        
/* Create a magenta bouncing ball */
        
glLoadName(SPHEREID);
        
glColor3f(0.6,0.0,0.6);
        if (
$drawquality DRAFT) {
            
glMaterialfv(GL_FRONT,GL_SHININESS,$mshin1);
            
glMaterialfv(GL_FRONT,GL_SPECULAR,$mspec1);
        }
        
glPushMatrix();
        
glTranslatef(0.0,$radius+0.5*(1+sin(M_PI*$theta/180)),0.0);
        
glScalef($radius,$radius,$radius);
        if (
$ballbounce)
            
$theta += $ballspeed;
        if (
$drawquality DRAFT)
            
glutSolidSphere(1.0,16,16);
        else
            
glutWireSphere(1.0,32,32);
        
glPopMatrix();
   
        
/* Create a white half-oval loop at one end */
        
glLoadName(OVALID);
        
glBegin(GL_LINE_STRIP);
        
glColor3f(1.0,1.0,1.0);
        
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
        for (
$i=0;$i<=180;$i++)
            
glVertex3f(2*cos($i*M_PI/180),1.5*sin($i*M_PI/180),-2.0);
        
glEnd();

        
/* Write some text */
        
glLoadName(TEXTID);
        
DrawTextXY(-2.0,-0.25,2.0,0.002,"PHP OpenGL Demo");
    }

    
/*
       Set up the lighing environment
    */
    
function MakeLighting() {
        global 
$drawquality;

        
$globalambient = array(0.3,0.3,0.3,1.0);

        
/* The specifications for 3 light sources */
        
$pos0 = array(1.0,1.0,0.0,0.0);      /* w = 0 == infinite distance */
        
$dif0 = array(0.8,0.8,0.8,1.0);

        
$pos1 = array(5.0,-5.0,0.0,0.0);   /* Light from below */
        
$dif1 = array(0.4,0.4,0.4,1.0);      /* Fainter */

        
if ($drawquality DRAFT) {

            
/* Set ambient globally, default ambient for light sources is 0 */
            
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,$globalambient);

            
glLightfv(GL_LIGHT0,GL_POSITION,$pos0);
            
glLightfv(GL_LIGHT0,GL_DIFFUSE,$dif0);

            
glLightfv(GL_LIGHT1,GL_POSITION,$pos1);
            
glLightfv(GL_LIGHT1,GL_DIFFUSE,$dif1);

            
glEnable(GL_LIGHT0);
            
glEnable(GL_LIGHT1);
            
glEnable(GL_LIGHTING);
        }
    }
    

    
/*
       Set up the camera
       Optionally creating a small viewport about 
       the mouse click point for object selection
    */
    
function MakeCamera($pickmode,$x,$y) {
        global 
$updownrotate$spincamera$cameradirection;
        static 
$theta 0;

        
$viewport = array();

        
/* Camera setup */
        
glMatrixMode(GL_PROJECTION);
        
glLoadIdentity();
        if (
$pickmode == TRUE) {
            
glGetIntegerv(GL_VIEWPORT,$viewport); /* Get the viewport bounds */
            
gluPickMatrix($x,$viewport[3]-$y,3.0,3.0,$viewport);
        }
        
gluPerspective(70.0,          /* Field of view */
                       
1.0,          /* aspect ratio  */
                       
0.1,1000.0);  /* near and far  */

        
glMatrixMode(GL_MODELVIEW);
        
glLoadIdentity();
        
gluLookAt(5*cos($theta*M_PI/180)*sin($updownrotate*M_PI/180),
                 
5*cos($updownrotate*M_PI/180),
                 
5*sin($theta*M_PI/180)*sin($updownrotate*M_PI/180), 
                 
0.0,0.0,0.0,                                   /* Focus    */
                 
0.0,1.0,0.0);                                  /* Up       */
        
if ($spincamera)
            
$theta += ($cameradirection 0.2);
    }

    
/*
       Deal with plain key strokes
    */
    
function HandleKeyboard($key,$x,$y) {
        global 
$spincamera$ballbounce;

        switch (
ord($key)) {
            case 
27/* ESC */
            
case ord('Q'):
            case 
ord('q'): exit(); break;
            case 
ord('s'):
            case 
ord('S'): $spincamera = !$spincamera; break;
            case 
ord('b'):
            case 
ord('B'): $ballbounce = !$ballbounce; break;
        }
    }

    
/*
       Deal with special key strokes
    */
    
function HandleSpecialKeyboard($key,$x,$y) {
        global 
$updownrotate$cameradirection;

        switch (
$key) {
            case 
GLUT_KEY_LEFT:  $cameradirection = -1; break;
            case 
GLUT_KEY_RIGHT$cameradirection 1;  break;
            case 
GLUT_KEY_UP:    $updownrotate -= 2;  break;
            case 
GLUT_KEY_DOWN:  $updownrotate += 2;  break;
        }
    }

    
/*
       Handle mouse events
    */
    
function HandleMouse($button,$state,$x,$y) {
    
        
$maxselect 100;
        
$nhits 0;
        
$selectlist = array();

        if (
$state == GLUT_DOWN) {
            
glSelectBuffer($maxselect);
            
glRenderMode(GL_SELECT);
            
glInitNames();
            
glPushName(-1);

            
glPushMatrix();
            
MakeCamera(TRUE,$x,$y);
            
MakeGeometry();
            
glPopMatrix();
            
$nhits glRenderMode(GL_RENDER);

            if (
$button == GLUT_LEFT_BUTTON) {

            } else if (
$button == GLUT_MIDDLE_BUTTON) {

            } 
/* Right button events are passed to menu handlers */

            
if ($nhits == -1)
                
error_log("Select buffer overflow");

            
$selectlist glGetSelectBuffer();
            
#var_dump($selectlist);
            
if ($nhits 0) {
                echo 
"\tPicked $nhits objects: ";
                for (
$i=0;$i<$nhits;$i++)
                    echo 
$selectlist[4*$i+3] . " ";
                echo 
"\n";
            }
        }
    }

    
/*
       Handle the main menu
    */
    
function HandleMainMenu($whichone) {
        global 
$spincamera$ballbounce;

        switch (
$whichone) {
            case 
1$spincamera = !$spincamera; break;
            case 
2$ballbounce = !$ballbounce; break;
            case 
100: exit(); break;
        }
    }

    
/*
       Handle the ball speed sub menu
    */
    
function HandleSpeedMenu($whichone) {
        global 
$ballspeed;
        
        switch (
$whichone) {
            case 
1$ballspeed 0.5; break;
            case 
2$ballspeed 2;   break;
            case 
3$ballspeed 10;  break;
        }
    }

    
/*
       How to handle visibility
    */
    
function HandleVisibility($visible) {

        if (
$visible == GLUT_VISIBLE)
            
glutIdleFunc('HandleIdle');
        else
            
glutIdleFunc(array());
    }

    
/*
       What to do on an idle event
    */
    
function HandleIdle() {

        
glutPostRedisplay();
    }

    
/*
       Draw text in the x-y plane
       The x,y,z coordinate is the bottom left corner (looking down -ve z axis)
    */
    
function DrawTextXY($x,$y,$z,$scale,$s) {

        
glPushMatrix();
        
glTranslatef($x,$y,$z);
        
glScalef($scale,$scale,$scale);
        for (
$i=0;$i<strlen($s);$i++)
            
glutStrokeCharacter(GLUT_STROKE_ROMAN,$s[$i]);
        
glPopMatrix();
    }

    
/*
       Display the program usage information
    */
    
function GiveUsage($cmd) {

        echo <<<USAGE
Usage:    $cmd [-h] [-q n]
          -h   this text
          -q n quality, 0,1,2

Key Strokes and Menus:
           q - quit
           s - toggle camera spin
           b - toggle ball bounce
  left arrow - change rotation direction
 right arrow - change rotation direction
  down arrow - rotate camera down
    up arrow - rotate camera up

USAGE;
            exit;
        }

?>