import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.awt.geom.*; import java.awt.image.*; import java.awt.image.ColorModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class BRDFView extends JApplet implements Runnable, MouseListener, ComponentListener, ChangeListener { Random generator = new Random(); BufferedImage offScreenImage; int width, height; int i = 0; Thread t = null; boolean threadSuspended; Font waterFont = new Font("Georgia", Font.PLAIN,20); boolean mousePressed = false; int length = 175; double angle; JPanel canvas = new JPanel(); JPanel controls = new JPanel(); sgSlider angleSlider = new sgSlider("Angle:",180,270,235); sgSlider glossSlider = new sgSlider("Shiny:",3,1000,10); boolean valid = false; int mouseX = -10; public void init() { addMouseListener(this); addComponentListener(this); angleSlider.slider.addChangeListener(this); glossSlider.slider.addChangeListener(this); controls.add(angleSlider,"West"); controls.add(glossSlider,"East"); add(canvas,"Center"); add(controls,"South"); } public void start() { if ( t == null ) { t = new Thread( this ); threadSuspended = false; t.start(); } else { if ( threadSuspended ) { threadSuspended = false; synchronized( this ) { notify(); } } } } public void stop() { threadSuspended = true; } // Executed within the thread that this applet created. public void run() { try { while (true) { // Now the thread checks to see if it should suspend itself if ( threadSuspended ) { synchronized( this ) { while ( threadSuspended ) { wait(); } } } update(canvas.getGraphics()); t.sleep( 1000/10 ); // interval given in milliseconds } } catch (InterruptedException e) { } } public void paint( Graphics g ) { width = canvas.getSize().width; height = canvas.getSize().height; angle = (angleSlider.getValue()-90)*Math.PI/180; Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setFont(waterFont); g2d.setStroke(new BasicStroke(1.5f)); g2d.setColor(Color.white); g2d.fillRect(0,0,width,height); g2d.translate(0,70); g2d.setColor(Color.black); g2d.drawLine(0,height/2,width,height/2); g2d.setColor(Color.blue); g2d.drawLine(width/2,height/2, (int)(width/2 - length*Math.cos(angle)), (int)(height/2-length*Math.sin(angle))); g2d.setColor(Color.green); g2d.drawLine(width/2,height/2, width/2,height/2-length); Path2D.Double brdf = new Path2D.Double(); brdf.moveTo(width/2,height/2); g2d.setColor(Color.gray); g2d.drawLine(175, height/2, 175, height/2-150); double val = 0, k,ai,ar; int gloss = glossSlider.getValue(); g2d.setColor(Color.black); if (gloss < 900) g2d.drawString("Phong",10,-50); else g2d.drawString("Mirror",10,-50); for (double i = 0; i < 120*Math.PI/180; i+=.05){ //generate reflected vector ai = angle - Math.PI/2; ar = Math.PI/2 - ai; g2d.setColor(Color.red); if (i == 0) g2d.drawLine(width/2,height/2, (int)(width/2 - 1.1*length*Math.cos(ar)), (int)(height/2-1.1*length*Math.sin(ar))); k = i - ar; val = length*Math.pow(Math.cos(k),gloss); if (gloss < 900) brdf.lineTo(width/2 - val*Math.cos(i), height/2 - val*Math.sin(i)); } brdf.lineTo(width/2,height/2); g2d.setPaint(new Color(.0f,.0f,.2f,.25f)); g2d.fill(brdf); g2d.setColor(Color.black); g2d.draw(brdf); controls.invalidate(); controls.repaint(); } static public void main(String [] argv){ BRDFView smonkaroni = new BRDFView(); JFrame frame = new JFrame("Blarg!"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(smonkaroni); frame.setSize(550,300); frame.setVisible(true); smonkaroni.init(); smonkaroni.start(); //yes, call it again. It's a hack frame.setSize(550,300); frame.setVisible(true); } public void mousePressed(MouseEvent e) { mousePressed = true; } public void mouseReleased(MouseEvent e) { mousePressed = false; } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } //perform double buffering manually public void update( Graphics g ){ if ( offScreenImage == null){ Image img = createImage( getSize().width, getSize().height ); Image img2 = createImage( getSize().width, getSize().height ); offScreenImage = (BufferedImage)img; } Graphics gOffScreenImage = offScreenImage.getGraphics(); //Now draw on the offscreen image. if (!valid) paint( gOffScreenImage ); g.drawImage(offScreenImage, 0, 0, this); gOffScreenImage.dispose(); } public void componentResized(ComponentEvent e) { offScreenImage = null; } public void componentMoved(ComponentEvent e) { } public void componentShown(ComponentEvent e) { } public void componentHidden(ComponentEvent e) { } public void stateChanged(ChangeEvent e) { valid = false; } } class sgSlider extends JPanel{ JLabel label; JSlider slider; int min,max; JPanel area; public sgSlider(String label, int min, int max, int value){ this.label = new JLabel(label); slider = new JSlider(min,max,value); add(this.label); add(slider); } public int getValue(){ return slider.getValue(); } } class sgText extends JPanel{ JLabel label; JTextField text; JPanel area; public sgText(String label, String value){ this.label = new JLabel(label); text = new JTextField(value,15); add(this.label); add(text); } public String getText(){ return text.getText(); } } class sgCheck extends JPanel{ JLabel label; JCheckBox check; JPanel area; public sgCheck(String label, boolean checked){ this.label = new JLabel(label); check = new JCheckBox(); check.setSelected(checked); add(this.label); add(check); } public boolean isChecked(){ return check.isSelected(); } }