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 Base 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,75); // Image icon = Toolkit.getDefaultToolkit().getImage("f:/sg.png"); boolean mousePressed = false; BufferedImage bottomRaster; JPanel canvas = new JPanel(); JPanel controls = new JPanel(); sgText title = new sgText("Text:","Facetious"); sgSlider rate = new sgSlider("Rate",0,50,30); sgCheck invert = new sgCheck("Invert", true); sgSlider textHeight = new sgSlider("Float",-50,50,2); String lastText; boolean lastInvert; boolean valid = false; boolean showControls = true; int mode = 1; public void init() { addMouseListener(this); addComponentListener(this); rate.slider.addChangeListener(this); textHeight.slider.addChangeListener(this); String passedText = null; try{ passedText = getParameter("text"); mode = Integer.parseInt(getParameter("mode")); if (getParameter("invert").equals("false")){ invert.check.setSelected(false); } if (getParameter("controls").equals("false")){ showControls = false; } rate.slider.setValue(Integer.parseInt(getParameter("rate"))); textHeight.slider.setValue(Integer.parseInt(getParameter("textHeight"))); }catch(Exception e){ System.out.println("No params.");}; add(canvas); if (showControls){ controls.setLayout(new GridLayout(2,2)); controls.add(title,0); controls.add(rate,1); controls.add(invert,2); controls.add(textHeight,3); add(controls,"South"); } if (passedText == null){ String [] dictionary = {"Facetious", "Whimsical", "Acrimonious", "Aesthetic", "Mundane", "Succinct", "Ostentatious","Resilient","Recalcitrant","Fallacious","Discernible","Truncate","Unctuous","Meticulous","Ludicrous"}; int which = (int)(dictionary.length*Math.random()); title.text.setText(dictionary[which]); } else{ title.text.setText(passedText); } } 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(); } } } if (!title.getText().equals(lastText) || !invert.check.isSelected() == lastInvert){ valid = false; lastText = title.getText(); lastInvert = invert.check.isSelected(); } 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; Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (invert.isChecked()) g2d.setColor(Color.black); else g2d.setColor(Color.white); g2d.fillRect(0,0,width,height/2+1); if (invert.isChecked()) g2d.setColor(Color.white); else g2d.setColor(Color.black); g2d.setFont(waterFont); FontMetrics ruler = g.getFontMetrics(waterFont); int stringWidth = ruler.stringWidth(title.getText()); g2d.drawString(title.getText(),width/2-stringWidth/2,height/2 + 1 -textHeight.getValue()); // g2d.drawImage(icon,width/2-stringWidth/2-40,20,width/2-stringWidth/2,height/2,0,0,icon.getWidth(this),icon.getHeight(this),this); //g2d.drawImage(icon,100,textHeight.getValue(),this); int mirror; if (!invert.isChecked()){ g2d.setColor(new Color(1.f,1.f,1.f,.40f)); // g2d.fillOval(0,-55 - textHeight.getValue(),width,2*height/3); } try{ if (mode == 0){ //mirror the image for(int j = height/2; j < height; j++){ for(int i = 0; i < width; i++){ mirror = offScreenImage.getRGB(i,height/2 -(j-height/2)); offScreenImage.setRGB(i,j,mirror); } float falloff = ((j-(height/2.f) + height/2*rate.getValue()/50))/(height/2.f); falloff = Math.min(1.f,falloff); if (invert.isChecked()) g2d.setColor(new Color(0.f,0.f,0.f, falloff)); else g2d.setColor(new Color(1.f,1.f,1.f, falloff)); g2d.drawLine(0,j,width,j); } } else{ //mirror and blur the image simultaneously int kernelSize = 40; int halfHeight = height/2; float [] kernel = new float[2*kernelSize + 1]; //blur horizontally for(int j = halfHeight; j <= height; j++){ //calculate the width based on the distance from the baseline float fWidth = rate.getValue()*((float)j-halfHeight)/(halfHeight); //populate the kernal based on the width int index = 0, hg; for (int k = -kernelSize; k <= kernelSize; k++){ kernel[index] = (float)Math.exp(-k*k/(2.f*fWidth*fWidth)); index++; } //must clear a singularity if (j == halfHeight) kernel[kernelSize] = 1.f; sgColor stack = new sgColor(); hg = height - j; //blur horizontally for(int i = 0; i < width; i++){ stack.clear(); //accumulate and weigh the kernel index = 0; for (int k = -kernelSize; k <= kernelSize; k++){ //handle the edges if (i+k < 0 || i + k > width - 1) stack.weightedAdd(offScreenImage.getRGB(0,hg),kernel[index]); else stack.weightedAdd(offScreenImage.getRGB(i+k,hg),kernel[index]); index++; } bottomRaster.setRGB(i,j,stack.getColor()); } } //blur vertically for(int j = height/2; j < height; j++){ //calculate the width based on the distance from the baseline float fWidth = rate.getValue()*(j-height/2.f)/(height/2.f); //populate the kernal based on the width int index = 0; for (int k = -kernelSize; k <= kernelSize; k++){ kernel[index] = (float)Math.exp(-k*k/(2*fWidth*fWidth)); index++; } //must clear a singularity if (j == halfHeight) kernel[kernelSize] = 1.f; sgColor stack = new sgColor(); //blur horizontally for(int i = 0; i < width; i++){ stack.clear(); //accumulate and weigh the kernel index = 0; for (int k = -kernelSize; k <= kernelSize; k++){ if (j-k >= height) stack.weightedAdd(bottomRaster.getRGB(i, height-1),kernel[index]); else stack.weightedAdd(bottomRaster.getRGB(i, j-k),kernel[index]); index++; } offScreenImage.setRGB(i,j,stack.getColor()); //we have successfully updated the image valid = true; } } } } catch(Exception e){ System.out.println("Buffer not ready yet:" + e); }; if (showControls){ controls.invalidate(); controls.repaint(); } } static public void main(String [] argv){ Base smonkaroni = new Base(); JFrame frame = new JFrame("Blarg!"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(smonkaroni); frame.setSize(540,300); frame.setVisible(true); smonkaroni.init(); smonkaroni.start(); //yes, call it again. It's a hack frame.setSize(600,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 ){ try{ if ( offScreenImage == null){ int height = canvas.getSize().height ; Image img = createImage( width, height ); Image img2 = createImage(width, height + 1); offScreenImage = (BufferedImage)img; bottomRaster = (BufferedImage)img2; } Graphics gOffScreenImage = offScreenImage.getGraphics(); //Now draw on the offscreen image. if (!valid) paint( gOffScreenImage ); g.drawImage(offScreenImage, 0, 0, this); gOffScreenImage.dispose(); }catch (Exception e ){}; } 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; //I really wanted to call this here, but I have to hack around it //update(canvas.getGraphics()); } } 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(); } } class sgColor{ int r,g,b; float accum; public sgColor(){ r = g = b = 0; accum = 0; } public sgColor(int rgb){ r += rgb >> 16 & 0xFF; g += rgb >> 8 & 0xFF; b += rgb & 0xFF; accum = 1; } public void add(int rgb){ r += rgb >> 16 & 0xFF; g += rgb >> 8 & 0xFF; b += rgb & 0xFF; accum++; } public void weightedAdd(int rgb, float weight){ r += (rgb >> 16 & 0xFF)*weight; g += (rgb >> 8 & 0xFF)*weight; b += (rgb & 0xFF)*weight; accum += weight; } public void sub(sgColor rgb){ r -= rgb.r; g -= rgb.g; b -= rgb.b; accum--; } public int getColor(){ return (((int)(r/accum))<<16) | (((int)(g/accum))<< 8) | ((int)(b/accum)); } public void clear(){ r = g = b = 0; accum = 0; } }