// jogl conversion of the redbook convolution example.  works in jogl 1.1.

// modified jplewis jul06 blindly adapting to new jogl jsr231, 
// 1) using direct nio arrays rather than simple float arrays for 
// glConvolution2D, also use direct byte array for drawpixels.
// 2) glDrawable -> glAutoDrawable
// 3) way of obtaining canvas has changed.
// seems to work.

// It uses a non-standard image file looding library, you will need
// to replace this.  See "replace" comments

/*
 * Copyright (c) 1993-2003, Silicon Graphics, Inc.
 * All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright
 * notice and this permission notice appear in supporting documentation,
 * and that the name of Silicon Graphics, Inc. not be used in
 * advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.
 *
 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND
 * WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
 * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, LOSS OF
 * PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD
 * PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN ADVISED OF
 * THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 *
 * US Government Users Restricted Rights 
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
 * (c)(1)(ii) of the Rights in Technical Data and Computer Software
 * clause at DFARS 252.227-7013 and/or in similar or successor clauses
 * in the FAR or the DOD or NASA FAR Supplement.  Unpublished - rights
 * reserved under the copyright laws of the United States.
 *
 * Contractor/manufacturer is:
 *      Silicon Graphics, Inc.
 *      1500 Crittenden Lane
 *      Mountain View, CA  94043
 *      United State of America
 *
 * OpenGL(R) is a registered trademark of Silicon Graphics, Inc.
 */

/*
 *  convolution.c
 *  Use various 2D convolutions filters to find edges in an image.
 *  
 */

import java.awt.*;
import java.awt.event.*;
import java.nio.*;
 
//import net.java.games.jogl.*;
//import net.java.games.jogl.util.*;
import javax.media.opengl.*;
import com.sun.opengl.util.*;

import GR.*;	// custom image class, replace
 
public class JoglConvolution
{

  static GLCanvas	canvas;
  static ByteBuffer 	pixels;
  static int   		width, height;

  static final int	CONV_NONE = 100;
  static final int	CONV_HORIZONTAL = 101;
  static final int	CONV_VERTICAL = 102;
  static final int	CONV_LAPLACE = 103;
  static int		convType = CONV_NONE;

  static float[]  horizontalarr = new float[] {
     0.f, -1.f, 0.f,  
     0.f,  1.f, 0.f, 
     0.f,  0.f, 0.f 
  };

  static float[]  verticalarr = new float[] {
     0.f, 0.f, 0.f,
    -1.f, 1.f, 0.f,
     0.f, 0.f, 0.f
  };

  static float[]  laplacianarr = new float[] {
     -0.125f, -0.125f, -0.125f,
     -0.125f,  1.f  ,  -0.125f,
     -0.125f, -0.125f, -0.125f
  };

  // zilla 06
  static ByteBuffer bbhorizontal = ByteBuffer.allocateDirect(9*4);
  static ByteBuffer bbvertical = ByteBuffer.allocateDirect(9*4);
  static ByteBuffer bblaplacian = ByteBuffer.allocateDirect(9*4);

  static {
    // needed!  otherwise result is black!
    bbhorizontal.order(ByteOrder.nativeOrder());
    bbvertical.order(ByteOrder.nativeOrder());
    bblaplacian.order(ByteOrder.nativeOrder());
  }

  static FloatBuffer horizontal = bbhorizontal.asFloatBuffer();
  static FloatBuffer vertical = bbvertical.asFloatBuffer();
  static FloatBuffer laplacian = bblaplacian.asFloatBuffer();

  static {
    horizontal.put(horizontalarr);  	horizontal.rewind();
    vertical.put(verticalarr); 		vertical.rewind();
    laplacian.put(laplacianarr);	laplacian.rewind();
  }



  public static void main(String[] args)
  {

    gr[] pic = grUtil.load(args[0]);	// replace
    byte[] pixels1 = tobyte3(pic);
    pixels = ByteBuffer.allocateDirect(pixels1.length);
    pixels.put(pixels1);
    pixels.rewind();

    Frame frame = new Frame("convolution");
    //frame.setUndecorated(true);
    // this was in 2005 version:
    //canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities());
    canvas = new GLCanvas(new GLCapabilities());
    canvas.addGLEventListener(new Renderer());
    frame.add(canvas);
    frame.setSize(width, height);
   
    frame.addWindowListener(new WindowAdapter() {
	public void windowClosing(WindowEvent e) {
	  // calling System.exit() synchronously inside the draw,
	  // reshape or init callbacks can lead to deadlocks on certain
	  // platforms (in particular, X11) because the JAWT's locking
	  // routines cause a global AWT lock to be grabbed. Run the
	  // exit routine in another thread.
	  new Thread(new Runnable() {
	      public void run() {
		//animator.stop();
		System.exit(0);
	      }
	    }).start();
	}});
    frame.setVisible(true);
    canvas.requestFocus();
  } //main


  static class Renderer implements GLEventListener, KeyListener
  {

    public void init(GLAutoDrawable gLDrawable)	// 2006 GLDrawable -> GLAuto..
    {
      final GL gl = gLDrawable.getGL();
      gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1);
      gl.glClearColor(0.f, 0.f, 0.f, 1.f);	// 

      System.out.println("Using the horizontal filter");
      gl.glConvolutionFilter2D(gl.GL_CONVOLUTION_2D, gl.GL_LUMINANCE, 3, 3,
			       gl.GL_LUMINANCE, gl.GL_FLOAT, horizontal);
      gl.glEnable(gl.GL_CONVOLUTION_2D);
      gLDrawable.addKeyListener(this);
    }


    // 2005 version
    //public void display(GLDrawable gLDrawable)

    public void display(GLAutoDrawable gLDrawable)
    {
      final GL gl = gLDrawable.getGL();

      switch(convType) {
      case CONV_NONE:
	gl.glDisable(gl.GL_CONVOLUTION_2D);
	break;

      case CONV_HORIZONTAL:
	gl.glEnable(gl.GL_CONVOLUTION_2D);
	horizontal.rewind();
	gl.glConvolutionFilter2D(gl.GL_CONVOLUTION_2D, gl.GL_LUMINANCE, 3, 3,
				 gl.GL_LUMINANCE, gl.GL_FLOAT, horizontal);
	break;

      case CONV_VERTICAL:
	gl.glEnable(gl.GL_CONVOLUTION_2D);
	vertical.rewind();
	gl.glConvolutionFilter2D(gl.GL_CONVOLUTION_2D, gl.GL_LUMINANCE, 3, 3,
				 gl.GL_LUMINANCE, gl.GL_FLOAT, vertical);
	break;

      case CONV_LAPLACE:
	gl.glEnable(gl.GL_CONVOLUTION_2D);
	laplacian.rewind();
	gl.glConvolutionFilter2D(gl.GL_CONVOLUTION_2D, gl.GL_LUMINANCE,
				 3, 3,
				 gl.GL_LUMINANCE, gl.GL_FLOAT,
				 laplacian);
	break;
      }

      gl.glClear(gl.GL_COLOR_BUFFER_BIT);
      gl.glRasterPos2i( 0, 0);	// original example was 1,1 but think 0,0 is correct
      pixels.rewind();
      gl.glDrawPixels(width, height, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, pixels);
      gl.glFlush();
    }

    public void displayChanged(GLAutoDrawable gLDrawable, boolean modeChanged, boolean deviceChanged)
    {
    }

    // this was in 2005 version
    //public void displayChanged(GLDrawable gLDrawable, boolean modeChanged, boolean deviceChanged)
    //{
    //}

    // 2005 version
    //public void reshape(GLDrawable gLDrawable, int x, int y, int w, int h)
    public void reshape(GLAutoDrawable gLDrawable, int x, int y, int w, int h)
    {
      final GL gl = gLDrawable.getGL();
      gl.glViewport(0, 0, w, h);
      gl.glMatrixMode(gl.GL_PROJECTION);
      gl.glLoadIdentity();
      gl.glOrtho(0, w, 0, h, -1.0, 1.0);
      gl.glMatrixMode(gl.GL_MODELVIEW);
     
    }


    public void keyPressed(KeyEvent e)
    {
      System.out.println("keyPressed "+e);
      if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
        System.exit(0);

      switch (e.getKeyCode()) {
      case KeyEvent.VK_H :
	System.out.println("Using a horizontal filter");
	// signal convolution setup to happen in display() thread not here
	convType = CONV_HORIZONTAL;
	break;

      case KeyEvent.VK_V:
	System.out.println("Using the vertical filter");
	convType = CONV_VERTICAL;
	break;

      case KeyEvent.VK_L:
	System.out.println("Using the laplacian filter");
	convType = CONV_LAPLACE;
	break;

      case KeyEvent.VK_N:
	System.out.println("no convolution");
	convType = CONV_NONE;
	break;

      } //switch

      //gl.glutPostRedisplay();
      canvas.display();
    } //keyPressed

    public void keyReleased(KeyEvent e) {}
   
    public void keyTyped(KeyEvent e) {}

  } //Renderer


  // replace this with your own image loader
  static byte[] tobyte3(gr[] pic)
  {
    width = pic[0].xres();
    height = pic[0].yres();
    System.out.println("res = "+width+","+height);
    byte[] pixels = new byte[3*width*height];
    int off = 0;

    for( int iyy=0; iyy < height; iyy++ ) {
      int iy = (height-1) - iyy;
      for( int ix=0; ix < width; ix++ ) {

	int v = pic[0].rd(ix,iy);
	v = (int)((255.f / gr.DTMAX) * v);
	if (v > 127) v = v - 256;
	pixels[off++] = (byte)v;

	v = pic[1].rd(ix,iy);
	v = (int)((255.f / gr.DTMAX) * v);
	if (v > 127) v = v - 256;
	pixels[off++] = (byte)v;

	v = pic[2].rd(ix,iy);
	v = (int)((255.f / gr.DTMAX) * v);
	if (v > 127) v = v - 256;
	pixels[off++] = (byte)v;

      }
    } //iy

    return pixels;
  } //tobyte3

} //JoglConvolution
