/*
 pellucid
 VRML 2.0 shading model applet
 by Eric Haines, erich@acm.org, copyright (c) 1997
    version 1.1
    3/13/97

 You may freely use and redistribute this code as long as you preserve the
 author and copyright information above.

 This applet simulates the VRML shading model given a default view of a sphere,
 a default directional light with direction -1 -1 -1, and a default material.
 I set the ambientIntensity for the light to be 1 (the default is 0) so that
 the ambientIntensity for the Material will have an effect immediately.
 The lighting and material fields can be modified, as well as the background
 color and the gamma correction factor for the monitor (see
 http://www.color.org for some notes on this, esp the sRGB paper, along with
 Poynton's page, http://www.inforamp.net/~poynton/Poynton-colour.html).

 history:
    3/6/97 - created 1.0
    3/13/97 - released 1.1: added clamping, erased sphere during recompute,
              changed defaults to be more interesting and useful.
 */

import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.util.*;
import java.io.*;
import java.net.*;

public class pellucid extends Applet
{
	// STANDALONE APPLICATION SUPPORT:
	//		m_fStandAlone will be set to true if applet is run standalone
	//--------------------------------------------------------------------------
	boolean m_fStandAlone = false;

	// STANDALONE APPLICATION SUPPORT
	// 	The main() method acts as the applet's entry point when it is run
	// as a standalone application. It is ignored if the applet is run from
	// within an HTML page.
	//--------------------------------------------------------------------------
	public static void main(String args[])
	{
		// Create Toplevel Window to contain applet pellucid
		//----------------------------------------------------------------------
		pellucidFrame frame = new pellucidFrame("pellucid");

		// Must show Frame before we size it so insets() will return valid values
		//----------------------------------------------------------------------
		frame.show();
		frame.hide();
		frame.resize(frame.insets().left + frame.insets().right  + 505,
					 frame.insets().top  + frame.insets().bottom + 470);

		// The following code starts the applet running within the frame window.
		// It also calls GetParameters() to retrieve parameter values from the
		// command line, and sets m_fStandAlone to true to prevent init() from
		// trying to get them from the HTML page.
		//----------------------------------------------------------------------
		pellucid applet_pellucid = new pellucid();

		frame.add("Center", applet_pellucid);
		applet_pellucid.m_fStandAlone = true;
		applet_pellucid.init();
		applet_pellucid.start();
		frame.show();
	}

	// pellucid Class Constructor
	//--------------------------------------------------------------------------
	public pellucid()
	{
	}

	// APPLET INFO SUPPORT:
	//		The getAppletInfo() method returns a string describing the applet's
	// author, copyright date, or miscellaneous information.
    //--------------------------------------------------------------------------
	public String getAppletInfo()
	{
		return "Name: pellucid\r\n" +
		       "Author: Eric Haines\r\n" +
		       "Copyright 1997, all rights reserved";
	}


	// The init() method is called by the AWT when an applet is first loaded or
	// reloaded.  Override this method to perform whatever initialization your
	// applet needs, such as initializing data structures, loading images or
	// fonts, creating frame windows, setting the layout manager, or adding UI
	// components.
    //--------------------------------------------------------------------------
	public void init()
	{
		GUIInit();
	}

	// Place additional applet clean up code here.  destroy() is called when
	// when you applet is terminating and being unloaded.
	//-------------------------------------------------------------------------
	public void destroy()
	{
	}

	// pellucid Paint Handler
	//--------------------------------------------------------------------------
	public void paint(Graphics g) 
	{
		Image image;
		image = createImage(new MemoryImageSource(xres, yres, 
		    pixels, 0, xres));
		g.drawImage(image, 225, 270, null);
	}

	private void UpdateValues()
	{
		vLtSwitch = lightSwitch.getState() ;

		vLtIntensity = Double.valueOf(ltIntensity.getText()).doubleValue();
		vLtAmbInt = Double.valueOf(ltAmbInt.getText()).doubleValue();
		vLtColorR = Double.valueOf(ltColorR.getText()).doubleValue();
		vLtColorG = Double.valueOf(ltColorG.getText()).doubleValue();
		vLtColorB = Double.valueOf(ltColorB.getText()).doubleValue();
		vLtDirX = Double.valueOf(ltDirX.getText()).doubleValue();
		vLtDirY = Double.valueOf(ltDirY.getText()).doubleValue();
		vLtDirZ = Double.valueOf(ltDirZ.getText()).doubleValue();
		vAmbientInt = Double.valueOf(ambientInt.getText()).doubleValue();
		vDiffColorR = Double.valueOf(diffColorR.getText()).doubleValue();
		vDiffColorG = Double.valueOf(diffColorG.getText()).doubleValue();
		vDiffColorB = Double.valueOf(diffColorB.getText()).doubleValue();
		vShininess = Double.valueOf(shininess.getText()).doubleValue();
		vSpecColorR = Double.valueOf(specColorR.getText()).doubleValue();
		vSpecColorG = Double.valueOf(specColorG.getText()).doubleValue();
		vSpecColorB = Double.valueOf(specColorB.getText()).doubleValue();
		vTransparency = Double.valueOf(transparency.getText()).doubleValue();
		vEmColorR = Double.valueOf(emColorR.getText()).doubleValue();
		vEmColorG = Double.valueOf(emColorG.getText()).doubleValue();
		vEmColorB = Double.valueOf(emColorB.getText()).doubleValue();
		vBgColorR = Double.valueOf(bgColorR.getText()).doubleValue();
		vBgColorG = Double.valueOf(bgColorG.getText()).doubleValue();
		vBgColorB = Double.valueOf(bgColorB.getText()).doubleValue();
		vGamma = Double.valueOf(gammaCorr.getText()).doubleValue();
		vClampSwitch = clampSwitch.getState() ;
	}
	private void SetupImageCompute()
	{
		if ( vGamma <= 0.0 ) {
			vGamma = 1.0 ;
		}
		vInvGamma = 1.0 / vGamma ;
		hasGamma = ( vGamma != 1.0 ) ;

		// compute background colors
		dR = vBgColorR ;
		dG = vBgColorG ;
		dB = vBgColorB ;
		if ( hasGamma ) {
		    dR = Math.pow( dR, vInvGamma ) ;
		    dG = Math.pow( dG, vInvGamma ) ;
		    dB = Math.pow( dB, vInvGamma ) ;
		}

		if ( dR > 1.0 ) { dR = 1.0 ; }
		if ( dG > 1.0 ) { dG = 1.0 ; }
		if ( dB > 1.0 ) { dB = 1.0 ; }
		if ( dR < 0.0 ) { dR = 0.0 ; }
		if ( dG < 0.0 ) { dG = 0.0 ; }
		if ( dB < 0.0 ) { dB = 0.0 ; }
		bgColor = new Color( (int)(dR * 255), (int)(dG * 255), (int)(dB * 255) ) ;

		// compute fill foreground color: ambient + emissive
		fillR = vEmColorR ;
		fillG = vEmColorG ;
		fillB = vEmColorB ;

		if ( vLtSwitch ) {
			// add in ambient * light's ambient
			double totAmbInt = vLtAmbInt * vAmbientInt ;
			fillR += vDiffColorR * totAmbInt * vLtColorR ;
			fillG += vDiffColorG * totAmbInt * vLtColorG ;
			fillB += vDiffColorB * totAmbInt * vLtColorB ;
		}

		// set up constant background blend color
		blend = 1.0 - vTransparency ;

		if ( vTransparency > 0.0 ) {
			bgBlendR = vBgColorR * vTransparency ;
			bgBlendG = vBgColorG * vTransparency ;
			bgBlendB = vBgColorB * vTransparency ;
		}

		// normalize light direction
		length = vLtDirX * vLtDirX + vLtDirY * vLtDirY + vLtDirZ * vLtDirZ ;
		length = Math.sqrt( length ) ;
		if ( length == 0.0 ) {
			// bad lighting - set to default
			vLtDirX = 0 ;
			vLtDirY = 0 ;
			vLtDirZ = -1 ;
		} else {
			vLtDirX /= length ;
			vLtDirY /= length ;
			vLtDirZ /= length ;
		}

		// negate light direction to make N dot L computation easier
		vLtDirX = -vLtDirX ;
		vLtDirY = -vLtDirY ;
		vLtDirZ = -vLtDirZ ;

		// precompute light intensity * light color * diffuse color
		ldR = vLtIntensity * vLtColorR * vDiffColorR ;
		ldG = vLtIntensity * vLtColorG * vDiffColorG ;
		ldB = vLtIntensity * vLtColorB * vDiffColorB ;

		// common case: specular color off - check for it
		hasSpecular = (( vSpecColorR > 0.0 ) ||
							   ( vSpecColorG > 0.0 ) ||
							   ( vSpecColorB > 0.0 )) ;

		// precompute light intensity * light color * specular color
		lsR = vLtIntensity * vLtColorR * vSpecColorR ;
		lsG = vLtIntensity * vLtColorG * vSpecColorG ;
		lsB = vLtIntensity * vLtColorB * vSpecColorB ;

		// precompute shininess power
		shinePow = vShininess * 128 ;
		// note: we force shinePow to always be >= 1.0 here.
		// the spec doesn't require this, but it's nicer
		if ( shinePow < 1.0 ) { shinePow = 1.0 ; }
	}
	public void computeImage() 
	{
		// these two things are done separately due to a bug in javac,
		// which won't let you compile if you put all this code together
		UpdateValues() ;
		SetupImageCompute() ;

		// make the image flicker on purpose, so user knows when
		// the computation has taken place
		int ix, iy ;
		if ( doFlicker ) {
			for ( iy = 0 ; iy < yres ; iy++ ) {
				for ( ix = 0 ; ix < xres ; ix++ ) {
					pixels[iy*xres + ix] = bgColor.getRGB();
				}
			}
			paint(getGraphics());
		}

		double xscale = 2.2 / (double)yres ;
		double xoff = (double)xres * 1.1 / (double)yres ;

		// now go through each pixel and compute as needed
		double NdotL, NdotLV, contrib ;
		double LplusVx, LplusVy, LplusVz ;
		double totR, totG, totB ;
		Color sphClr ;
		for ( iy = 0 ; iy < yres ; iy++ ) {
			y = -( ( (double)iy / (double)yres ) * 2.2 - 1.1 ) ;
			y2 = y * y ;
			isBg = y2 > 1.0 ;
			for ( ix = 0 ; ix < xres ; ix++ ) {
				x = (double)ix * xscale - xoff ;
				x2 = x * x ;

				if ( isBg || x2 + y2 > 1.0 ) {
					// use background color, not in sphere
					pixels[iy*xres + ix] = bgColor.getRGB();
				} else {
					// set up emissive & ambient
					totR = fillR ;
					totG = fillG ;
					totB = fillB ;

					// is light on?
					if ( vLtSwitch ) {

						// compute diffuse component
						z = Math.sqrt( 1 - x2 - y2 ) ;
						// N . L
						NdotL = x * vLtDirX + y * vLtDirY + z * vLtDirZ ;

						if ( NdotL > 0.0 ) {
							// facing light
							totR += ldR * NdotL ;
							totG += ldG * NdotL ;
							totB += ldB * NdotL ;
						}

						// compute specular component
						if ( hasSpecular ) {
							// add in V (eye) vector of (0,0,1)
							// for our case we could actually precompute
							LplusVx = vLtDirX ;	// + eyeX
							LplusVy = vLtDirY ; // + eyeY
							LplusVz = vLtDirZ + 1 ;

							length = LplusVx * LplusVx + LplusVy * LplusVy + LplusVz * LplusVz ;
							length = Math.sqrt( length ) ;
							if ( length == 0.0 ) {
								// bad lighting - set to default
								LplusVx = 0 ;
								LplusVy = 0 ;
								LplusVz = 1 ;
							} else {
								LplusVx /= length ;
								LplusVy /= length ;
								LplusVz /= length ;
							}

							// N dot (L+V)
							NdotLV = x * LplusVx + y * LplusVy + z * LplusVz ;

							if ( NdotLV > 0.0 ) {
								contrib = Math.pow( NdotLV, shinePow ) ;
								totR += contrib * lsR ;
								totG += contrib * lsG ;
								totB += contrib * lsB ;
							}
						}
					}

					// compute transparency, if any
					if ( vTransparency > 0.0 ) {
						// blend background and foreground
						totR = totR * blend + bgBlendR ;
						totG = totG * blend + bgBlendG ;
						totB = totB * blend + bgBlendB ;
					}

					// clamp the color
					if ( vClampSwitch ) {
						if ( totR > 1.0 ||
						     totG > 1.0 ||
						     totB > 1.0 ) {
							// use clamp color
							totR = vClampR ;
							totG = vClampG ;
							totB = vClampB ;
						}
					} else {
						if ( totR > 1.0 ) { totR = 1.0 ; }
						if ( totG > 1.0 ) { totG = 1.0 ; }
						if ( totB > 1.0 ) { totB = 1.0 ; }
					}
					if ( totR < 0.0 ) { totR = 0.0 ; }
					if ( totG < 0.0 ) { totG = 0.0 ; }
					if ( totB < 0.0 ) { totB = 0.0 ; }

					// gamma correct
					if ( hasGamma ) {
						totR = Math.pow( totR, vInvGamma ) ;
						totG = Math.pow( totG, vInvGamma ) ;
						totB = Math.pow( totB, vInvGamma ) ;
					}
					sphClr = new Color( (int)(totR * 255), (int)(totG * 255), (int)(totB * 255) ) ;
					pixels[iy*xres + ix] = sphClr.getRGB();
				}
			}
		}
	}


	//		The start() method is called when the page containing the applet
	// first appears on the screen. The AppletWizard's initial implementation
	// of this method starts execution of the applet's thread.
	//--------------------------------------------------------------------------
	public void start()
	{
	}
	
	//		The stop() method is called when the page containing the applet is
	// no longer on the screen. The AppletWizard's initial implementation of
	// this method stops execution of the applet's thread.
	//--------------------------------------------------------------------------
	public void stop()
	{
	}
	
	public boolean handleEvent( Event event )
	{
		return super.handleEvent( event );
	}

	private void GUIInit()
	{
		setLayout( null );
		addNotify();
		resize( (insets().left + insets().right + 505), (insets().top + insets().bottom + 470) );

		lightSwitch = new Checkbox( "Light on", null, true );
		//lightSwitch.setBackground( new Color( 255, 255, 255 ));
		lightSwitch.setForeground( new Color( 128, 0, 255 ));
		add( lightSwitch );
		lightSwitch.addNotify();
		lightSwitch.reshape( (insets().left + 19), (insets().top + 25), 69, 19 );

		labelLtIntensity = new Label( "intensity", Label.RIGHT );
		//labelLtIntensity.setBackground( new Color( 255, 255, 255 ));
		labelLtIntensity.setForeground( new Color( 128, 0, 255 ));
		add( labelLtIntensity );
		labelLtIntensity.addNotify();
		labelLtIntensity.reshape( (insets().left + 114), (insets().top + 26), 65, 16 );

		ltIntensity = new TextField( "1" );
		ltIntensity.setEditable( true );
		//ltIntensity.setBackground( new Color( 255, 255, 255 ));
		ltIntensity.setForeground( new Color( 128, 0, 255 ));
		add( ltIntensity );
		ltIntensity.addNotify();
		ltIntensity.reshape( (insets().left + 197), (insets().top + 21), 45, 26 );

		labelLtAmbInt = new Label( "ambientIntensity", Label.RIGHT );
		//labelLtAmbInt.setBackground( new Color( 255, 255, 255 ));
		labelLtAmbInt.setForeground( new Color( 128, 0, 255 ));
		add( labelLtAmbInt );
		labelLtAmbInt.addNotify();
		labelLtAmbInt.reshape( (insets().left + 258), (insets().top + 26), 105, 16 );

		ltAmbInt = new TextField( "1" );
		ltAmbInt.setEditable( true );
		//ltAmbInt.setBackground( new Color( 255, 255, 255 ));
		ltAmbInt.setForeground( new Color( 128, 0, 255 ));
		add( ltAmbInt );
		ltAmbInt.addNotify();
		ltAmbInt.reshape( (insets().left + 384), (insets().top + 21), 45, 26 );

		labelLtColor = new Label( "color", Label.RIGHT );
		//labelLtColor.setBackground( new Color( 255, 255, 255 ));
		labelLtColor.setForeground( new Color( 128, 0, 255 ));
		add( labelLtColor );
		labelLtColor.addNotify();
		labelLtColor.reshape( (insets().left + 56), (insets().top + 62), 51, 16 );

		ltColorR = new TextField( "1" );
		ltColorR.setEditable( true );
		//ltColorR.setBackground( new Color( 255, 255, 255 ));
		ltColorR.setForeground( new Color( 128, 0, 255 ));
		add( ltColorR );
		ltColorR.addNotify();
		ltColorR.reshape( (insets().left + 120), (insets().top + 57), 45, 26 );

		ltColorG = new TextField( "1" );
		ltColorG.setEditable( true );
		//ltColorG.setBackground( new Color( 255, 255, 255 ));
		ltColorG.setForeground( new Color( 128, 0, 255 ));
		add( ltColorG );
		ltColorG.addNotify();
		ltColorG.reshape( (insets().left + 175), (insets().top + 57), 45, 26 );

		ltColorB = new TextField( "1" );
		ltColorB.setEditable( true );
		//ltColorB.setBackground( new Color( 255, 255, 255 ));
		ltColorB.setForeground( new Color( 128, 0, 255 ));
		add( ltColorB );
		ltColorB.addNotify();
		ltColorB.reshape( (insets().left + 230), (insets().top + 57), 45, 26 );

		labelLtDirection = new Label( "direction", Label.RIGHT );
		//labelLtDirection.setBackground( new Color( 255, 255, 255 ));
		labelLtDirection.setForeground( new Color( 128, 0, 255 ));
		add( labelLtDirection );
		labelLtDirection.addNotify();
		labelLtDirection.reshape( (insets().left + 37), (insets().top + 103), 71, 16 );

		ltDirX = new TextField( "-1" );
		ltDirX.setEditable( true );
		//ltDirX.setBackground( new Color( 255, 255, 255 ));
		ltDirX.setForeground( new Color( 128, 0, 255 ));
		add( ltDirX );
		ltDirX.addNotify();
		ltDirX.reshape( (insets().left + 120), (insets().top + 98), 45, 26 );

		ltDirY = new TextField( "-1" );
		ltDirY.setEditable( true );
		//ltDirY.setBackground( new Color( 255, 255, 255 ));
		ltDirY.setForeground( new Color( 128, 0, 255 ));
		add( ltDirY );
		ltDirY.addNotify();
		ltDirY.reshape( (insets().left + 175), (insets().top + 98), 45, 26 );

		ltDirZ = new TextField( "-1" );
		ltDirZ.setEditable( true );
		//ltDirZ.setBackground( new Color( 255, 255, 255 ));
		ltDirZ.setForeground( new Color( 128, 0, 255 ));
		add( ltDirZ );
		ltDirZ.addNotify();
		ltDirZ.reshape( (insets().left + 230), (insets().top + 98), 45, 26 );

		labelMaterial = new Label( "Material", Label.LEFT );
		add( labelMaterial );
		labelMaterial.addNotify();
		labelMaterial.reshape( (insets().left + 5), (insets().top + 146), 64, 16 );

		labelAmbInt = new Label( "ambientIntensity", Label.RIGHT );
		add( labelAmbInt );
		labelAmbInt.addNotify();
		labelAmbInt.reshape( (insets().left + 64), (insets().top + 146), 105, 16 );

		ambientInt = new TextField( "0.2" );
		ambientInt.setEditable( true );
		add( ambientInt );
		ambientInt.addNotify();
		ambientInt.reshape( (insets().left + 175), (insets().top + 141), 45, 26 );

		labelColor = new Label( "diffuseColor", Label.RIGHT );
		add( labelColor );
		labelColor.addNotify();
		labelColor.reshape( (insets().left + 236), (insets().top + 146), 80, 16 );

		diffColorR = new TextField( "0.8" );
		diffColorR.setEditable( true );
		add( diffColorR );
		diffColorR.addNotify();
		diffColorR.reshape( (insets().left + 330), (insets().top + 141), 45, 26 );

		diffColorG = new TextField( "0.8" );
		diffColorG.setEditable( true );
		add( diffColorG );
		diffColorG.addNotify();
		diffColorG.reshape( (insets().left + 385), (insets().top + 141), 45, 26 );

		diffColorB = new TextField( "0.8" );
		diffColorB.setEditable( true );
		add( diffColorB );
		diffColorB.addNotify();
		diffColorB.reshape( (insets().left + 440), (insets().top + 141), 45, 26 );

		labelShininess = new Label( "shininess", Label.RIGHT );
		add( labelShininess );
		labelShininess.addNotify();
		labelShininess.reshape( (insets().left + 73), (insets().top + 186), 73, 16 );

		shininess = new TextField( "0.2" );
		shininess.setEditable( true );
		add( shininess );
		shininess.addNotify();
		shininess.reshape( (insets().left + 155), (insets().top + 181), 45, 26 );

		specColor = new Label( "specularColor", Label.RIGHT );
		add( specColor );
		specColor.addNotify();
		specColor.reshape( (insets().left + 225), (insets().top + 183), 93, 16 );

		specColorR = new TextField( "0" );
		specColorR.setEditable( true );
		add( specColorR );
		specColorR.addNotify();
		specColorR.reshape( (insets().left + 330), (insets().top + 180), 45, 26 );

		specColorG = new TextField( "0" );
		specColorG.setEditable( true );
		add( specColorG );
		specColorG.addNotify();
		specColorG.reshape( (insets().left + 385), (insets().top + 181), 45, 26 );

		specColorB = new TextField( "0" );
		specColorB.setEditable( true );
		add( specColorB );
		specColorB.addNotify();
		specColorB.reshape( (insets().left + 440), (insets().top + 181), 45, 26 );

		labelTransparency = new Label( "transparency", Label.RIGHT );
		add( labelTransparency );
		labelTransparency.addNotify();
		labelTransparency.reshape( (insets().left + 53), (insets().top + 225), 93, 16 );

		transparency = new TextField( "0" );
		transparency.setEditable( true );
		add( transparency );
		transparency.addNotify();
		transparency.reshape( (insets().left + 155), (insets().top + 225), 45, 26 );

		emissiveColor = new Label( "emissiveColor", Label.RIGHT );
		add( emissiveColor );
		emissiveColor.addNotify();
		emissiveColor.reshape( (insets().left + 225), (insets().top + 225), 93, 16 );

		emColorR = new TextField( "0" );
		emColorR.setEditable( true );
		add( emColorR );
		emColorR.addNotify();
		emColorR.reshape( (insets().left + 330), (insets().top + 221), 45, 26 );

		emColorG = new TextField( "0" );
		emColorG.setEditable( true );
		add( emColorG );
		emColorG.addNotify();
		emColorG.reshape( (insets().left + 385), (insets().top + 222), 45, 26 );

		emColorB = new TextField( "0" );
		emColorB.setEditable( true );
		add( emColorB );
		emColorB.addNotify();
		emColorB.reshape( (insets().left + 440), (insets().top + 222), 45, 26 );

		labelBackgroundColor = new Label( "BackgroundColor", Label.RIGHT );
		add( labelBackgroundColor );
		labelBackgroundColor.addNotify();
		labelBackgroundColor.reshape( (insets().left + 14), (insets().top + 282), 117, 16 );

		bgColorR = new TextField( "0.2" );
		bgColorR.setEditable( true );
		add( bgColorR );
		bgColorR.addNotify();
		bgColorR.reshape( (insets().left + 147), (insets().top + 277), 45, 26 );

		bgColorG = new TextField( "0.2" );
		bgColorG.setEditable( true );
		add( bgColorG );
		bgColorG.addNotify();
		bgColorG.reshape( (insets().left + 147), (insets().top + 311), 45, 26 );

		bgColorB = new TextField( "0.2" );
		bgColorB.setEditable( true );
		add( bgColorB );
		bgColorB.addNotify();
		bgColorB.reshape( (insets().left + 147), (insets().top + 347), 45, 26 );

		labelGamma = new Label( "Gamma correction", Label.RIGHT );
		add( labelGamma );
		labelGamma.addNotify();
		labelGamma.reshape( (insets().left + 21), (insets().top + 389), 117, 16 );

		gammaCorr = new TextField( "2.2" );
		gammaCorr.setEditable( true );
		add( gammaCorr );
		gammaCorr.addNotify();
		gammaCorr.reshape( (insets().left + 147), (insets().top + 384), 45, 26 );

		clampSwitch = new Checkbox( "show clamp", null, false );
		clampSwitch.setForeground( new Color( 0, 128, 128 ));
		add( clampSwitch );
		clampSwitch.addNotify();
		clampSwitch.reshape( (insets().left + 380), (insets().top + 80), 100, 19 );

		computeButton = new RunButton( "Compute!" );
		add( computeButton );
		computeButton.addNotify();
		computeButton.reshape( (insets().left + 21), (insets().top + 422), 171, 26 );

		// set resolution of computed image
		xres = 260 ;
		yres = 180 ;
		pixels = new int[xres*(yres+1)];

		super.init();
	}

	Checkbox lightSwitch;
	Label labelLtIntensity;
	TextField ltIntensity;
	Label labelLtAmbInt;
	TextField ltAmbInt;
	Label labelLtColor;
	TextField ltColorR;
	TextField ltColorG;
	TextField ltColorB;
	Label labelLtDirection;
	TextField ltDirX;
	TextField ltDirY;
	TextField ltDirZ;
	Label labelMaterial;
	TextField ambientInt;
	Label labelAmbInt;
	Label labelColor;
	TextField diffColorR;
	TextField diffColorG;
	TextField diffColorB;
	Label labelShininess;
	TextField shininess;
	Label specColor;
	TextField specColorR;
	TextField specColorG;
	TextField specColorB;
	Label labelTransparency;
	TextField transparency;
	Label emissiveColor;
	TextField emColorR;
	TextField emColorG;
	TextField emColorB;
	Label labelBackgroundColor;
	TextField bgColorR;
	TextField bgColorG;
	TextField bgColorB;
	Label labelGamma;
	TextField gammaCorr;
	Checkbox clampSwitch;
	RunButton computeButton;

	private int pixels[] ;
	private int xres ;
	private int yres ;

	private boolean vLtSwitch ;

	private double vLtIntensity ;
	private double vLtAmbInt ;
	private double vLtColorR ;
	private double vLtColorG ;
	private double vLtColorB ;
	private double vLtDirX ;
	private double vLtDirY ;
	private double vLtDirZ ;
	private double vAmbientInt ;
	private double vDiffColorR ;
	private double vDiffColorG ;
	private double vDiffColorB ;
	private double vShininess ;
	private double vSpecColorR ;
	private double vSpecColorG ;
	private double vSpecColorB ;
	private double vTransparency ;
	private double vEmColorR ;
	private double vEmColorG ;
	private double vEmColorB ;
	private double vBgColorR ;
	private double vBgColorG ;
	private double vBgColorB ;
	private double vGamma ;
	private boolean vClampSwitch ;
	// set this to whatever clamp color you want
	private double vClampR = 0.8 ;
	private double vClampG = 0.0 ;
	private double vClampB = 0.0 ;
	// turn this off if you don't like the flicker effect
	private boolean doFlicker = true ;

	boolean isBg ;
	double x, y, x2, y2, z ;
	double vInvGamma ;
	boolean hasGamma ;
	double dR, dG, dB ;
	Color bgColor ;
	double fillR, fillG, fillB ;
	double bgBlendR, bgBlendG, bgBlendB ;
	double blend ;
	double length ;
	double ldR, ldG, ldB ;
	boolean hasSpecular ;
	double lsR, lsG, lsB ;
	double shinePow ;
}

class RunButton extends Button
{
	RunButton(String sText)
	{
		super(sText) ;
	}

	public boolean action(Event evt, Object arg) 
	{
		pellucid par = (pellucid)getParent();
		par.computeImage();
		par.paint(par.getGraphics());
		return true;
	}
}

//==============================================================================
// STANDALONE APPLICATION SUPPORT
// 	This frame class acts as a top-level window in which the applet appears
// when it's run as a standalone application.
//==============================================================================
class pellucidFrame extends Frame
{
	// pellucidFrame constructor
	//--------------------------------------------------------------------------
	public pellucidFrame(String str)
	{
		super (str);
	}

	// The handleEvent() method receives all events generated within the frame
	// window. You can use this method to respond to window events. To respond
	// to events generated by menus, buttons, etc. or other controls in the
	// frame window but not managed by the applet, override the window's
	// action() method.
	//--------------------------------------------------------------------------
	public boolean handleEvent(Event evt)
	{
		switch (evt.id)
		{
			// Application shutdown (e.g. user chooses Close from the system menu).
			//------------------------------------------------------------------
			case Event.WINDOW_DESTROY:
				dispose();
				System.exit(0);
				return true;

			default:
				return super.handleEvent(evt);
		}			 
	}
}

