import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.nio.ByteBuffer;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.jogamp.opengl.util.FPSAnimator;


public class AntiAlias implements GLEventListener, ActionListener, ChangeListener {

		public static void main(String[] args) {
			new AntiAlias();
		}
		
		public static final int INITIAL_WIDTH = 700;
		public static final int INITIAL_HEIGHT = 700;
		public static final int WIDTH = 600;
		public static final int HEIGHT = 600;
		private byte [] buffer = new byte[HEIGHT*WIDTH*4];
		JButton quitButton;
		JSlider slopeSlider;
		JLabel slopeLabel;
		float slope = 0.5f;
		GL2 gl;
		GLU glu;
		private GLCanvas canvas;
		
		

		public  AntiAlias() {
				GLProfile glp=GLProfile.getDefault();
				GLCapabilities caps = new GLCapabilities(glp);
				canvas = new GLCanvas(caps);
				
				JFrame frame = new JFrame("Bresenham (bottom) and Pitteway");
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
				frame.setSize(INITIAL_WIDTH, INITIAL_HEIGHT);
				frame.setLayout(new BorderLayout());
				
				JPanel controlPanel = new JPanel( new BorderLayout());
					quitButton = new JButton( "Quit");
					quitButton.addActionListener(this);
					controlPanel.add(quitButton, BorderLayout.WEST);

					JPanel slopeStuff = new JPanel( new FlowLayout());
					slopeStuff.add( new JLabel( "slope:"));
					slopeSlider = new JSlider(0, 50);
					slopeSlider.addChangeListener(this);
					Float [] L = new Float[1];
					L[0] = new Float(slope);
					slopeLabel = new JLabel(String.format( "%.1f", L));
					slopeSlider.setValue( (int)(slope*50));
					slopeStuff.add(slopeSlider);
					slopeStuff.add(slopeLabel);
					controlPanel.add(slopeStuff, BorderLayout.CENTER);
				frame.add(controlPanel, BorderLayout.SOUTH);
				
				JPanel center = new JPanel(new GridLayout(1,1));
				center.add(canvas);
				canvas.addGLEventListener(this);
				frame.add(center, BorderLayout.CENTER);
				
				frame.setVisible(true);
				
				FPSAnimator animator = new FPSAnimator(canvas, 60);
				animator.start(); 
					

		}
		public void actionPerformed(ActionEvent event) {
				if (event.getSource() == quitButton)
					System.exit(0);
			
		}
		
		public void stateChanged(ChangeEvent e) {
			slope = slopeSlider.getValue()/50.0f;
			Float [] L = new Float[1];
			L[0] = new Float(slope);
			slopeLabel.setText(String.format( "%.1f     ", L));	
}

		void setBuffer( byte dest[], int i, int j, float g) {
			byte gray = (byte)(g*127);
			int row = HEIGHT-i-1;
			dest[row*WIDTH*3+j*3]=gray;
			dest[row*WIDTH*3+j*3+1]=gray;
			dest[row*WIDTH*3+j*3+2]=gray;
	}

		public void  Bresenham(int x0, int y0, int x1, int y1 ) {
		  /* This draws a triangle, whose sloped edge is drawin with
		     Bresenham's algorithm */
			int h = x1-x0;
			int v = y1-y0;
			int d = 2*v-h;
			int y = y0;

			for (int x = x0; x <= x1; x++) {
				setBuffer(buffer, y, x, 0);   // this draws the edge

				for (int i=y+1; i <= y1; i++)  /* This draws the rest of the triangle */
					setBuffer(buffer, i, x, 0); 
				if (d <= 0) 
					d += 2*v;
				else {
					y += 1;
					d += 2*(v-h);
				}
			}
		}

		void Pitteway(int x0, int y0, int x1, int y1 )
		{
			int y = y0;
			float d = 0.5f;
			float m = (y1-y0)*1.0f/(x1-x0);
			for (int x = x0; x <= x1; x++ ) {
				setBuffer(buffer, y, x, 1f-d); // This draws the edge

				if (y < y1) {             /* This draws the rest of the triangle. */
					for (int i = y+1; i <= y1; i++) 
						setBuffer(buffer, i, x, 0);
				}
				if (d >= m) 
					d -= m;
				else {
					d += (1-m);
					y += 1;
				}
			}
		}

		void drawLines()
		{
			for (int i = 0;i < WIDTH; i++)   /* Initializes the bitmap to all white */
				for (int j=0; j < HEIGHT; j++)
					setBuffer(buffer, i, j, 1);

			gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
			int x0 = 50;
			int y0 = 250;
			int x1 = 350;
			int y1 = y0 + (int)(slope*300);

			Bresenham(x0, y0, x1, y1);
			x0 += 200;
			x1 += 200;
			y0 -= 200;
			y1 -= 200;
			Pitteway(x0, y0, x1, y1 );
			gl.glRasterPos2i((INITIAL_WIDTH-WIDTH)/2, 0);
			gl.glDrawPixels(WIDTH,  HEIGHT,  GL2.GL_RGB, GL2.GL_BYTE, ByteBuffer.wrap(buffer));
		}
		
		public void display(GLAutoDrawable drawable) {
			render();
		}
		
		public void render() {
			drawLines();

		}

		public void dispose(GLAutoDrawable drawable) {
			// put the cleanup code here	
		}

		public void init(GLAutoDrawable drawable) {
			gl = drawable.getGL().getGL2();
			glu = new GLU();
			gl.glClearColor(1,  1, 0.7f, 1);
			gl.glMatrixMode(GL2.GL_PROJECTION);
			gl.glLoadIdentity();
			glu.gluOrtho2D(0, INITIAL_WIDTH, 0, INITIAL_HEIGHT); 
			gl.glPixelStorei(GL2.GL_PACK_ALIGNMENT, 1);
			gl.glPixelStorei(GL2.GL_UNPACK_ALIGNMENT, 1);
			gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, 0);
			gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, 0);
//			buffer = new byte[HEIGHT*WIDTH*4];
}

		public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
			// this is called when the window is resized	
		}

}
