/*
 * HACKED ON BY FT... a lot. ;)
 */
/*
 * -based on code by Yuan-Chu Tai http://www.geocities.com/chobitsfan/
 * -an opengl idea from MPlayer http://www.mplayerhq.hu/homepage
 */

//gcc -Wall -lglut -ldc1394_control -lraw1394 -lGL -lGLU texture_sub.c -o texture_sub

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <libraw1394/raw1394.h>
#include <libdc1394/dc1394_control.h>



static dc1394_cameracapture camera;
static int numNodes;
static int numCameras;
static raw1394handle_t handle;
static nodeid_t * camera_nodes;
//static dc1394_feature_set features;

static GLenum errCode;
const GLubyte *errString;


//texture height and width have to be a mulptiple of 2
//should be bigger then the image height and width we want
#define TEX_WIDTH 1024
#define TEX_HEIGHT  1024

#define IMAGE_WIDTH 640
#define IMAGE_HEIGHT 480

//example of ROT90
#define ROT90 1

void ieee1394init()
{
    handle = dc1394_create_handle(0);
    numNodes = raw1394_get_nodecount(handle);
    camera_nodes = dc1394_get_camera_nodes(handle,&numCameras,1);
    dc1394_dma_setup_capture(handle,camera_nodes[0],
            0,
            FORMAT_VGA_NONCOMPRESSED,
            MODE_640x480_MONO,
            //MODE_640x480_RGB,
            SPEED_400,
            FRAMERATE_30,
            //FRAMERATE_7_5,
            4,
            &camera);

    printf("first camera\n");

    dc1394_start_iso_transmission(handle,camera.node);
}

void init(void)
{
    //nothing
    glClearColor (1.0, 0.0, 1.0, 0.0);
    glShadeModel(GL_FLAT);
    //glShadeModel(GL_SMOOTH);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    //don't need to do a lot of stuff because we're just drawing pixels anyway 
    //it's just video :)  
    glDisable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);

    glEnable(GL_TEXTURE_2D);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

    dc1394_dma_single_capture(&camera); //grab a frame

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_WIDTH,
            TEX_HEIGHT, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
            camera.capture_buffer);
    dc1394_dma_done_with_buffer(&camera);	
    glClear( GL_COLOR_BUFFER_BIT );

    if ((errCode = glGetError()) != GL_NO_ERROR) {
        errString = gluErrorString(errCode);
        fprintf (stderr, "OpenGL Error: %s\n", errString);
        exit(1);
    }

}

void display(void)
{
    int i;

    dc1394_dma_single_capture(&camera); //grab a frame

    /*
       glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, IMAGE_WIDTH,
       IMAGE_HEIGHT, GL_LUMINANCE, GL_UNSIGNED_BYTE,
       camera.capture_buffer);
       */

    //this is how MPlayer does it, but I don't really notice a speed 
    //increse compared glTexSubImage the whole image at once.
    for(i=0;i<IMAGE_HEIGHT;i++){
        glTexSubImage2D( GL_TEXTURE_2D,  // target
                0,              // level
                0,              // x offset
                i,              // y offset
                IMAGE_WIDTH,    // width
                1,              // height
                //(BYTES_PP==4)?GL_RGBA:GL_RGB,        // format
                GL_LUMINANCE,        // format
                GL_UNSIGNED_BYTE, // type
                &((char *)camera.capture_buffer)[i*1*IMAGE_WIDTH]); // *pixels
    }

    dc1394_dma_done_with_buffer(&camera);	

    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
    glTexCoord2f(0.0, 1.0); glVertex2f(0.0, TEX_HEIGHT);
    glTexCoord2f(1.0, 1.0); glVertex2f(TEX_WIDTH,TEX_HEIGHT);
    glTexCoord2f(1.0, 0.0); glVertex2f(TEX_WIDTH, 0.0);
    glEnd();
    glFinish();

    if ((errCode = glGetError()) != GL_NO_ERROR) {
        errString = gluErrorString(errCode);
        fprintf (stderr, "OpenGL Error: %s\n", errString);
        exit(1);
    }

    glutSwapBuffers();
}


void reshape(int w, int h)
{
    glViewport(0,0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (ROT90) {
        glOrtho(0, IMAGE_HEIGHT, IMAGE_WIDTH, 0, -1, 1);
        glRotated(90, 0,0,1 );
        glTranslatef(0,-480,0);
    } else {
        glOrtho(0, IMAGE_WIDTH, IMAGE_HEIGHT, 0, -1, 1);
    }
    //glRotated(180, 0,0,1 );
    //glTranslatef(-640,-480,0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

/* ARGSUSED1 */
void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
        case 27:
            exit(0);
            break;
    }
    glutPostRedisplay();
}


void spinDisplay(void)
{
    glutPostRedisplay();
}

int main(int argc, char** argv)
{
    ieee1394init();

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB );

    if (ROT90) {
        glutInitWindowSize(IMAGE_HEIGHT, IMAGE_WIDTH);
    } else {
        glutInitWindowSize(IMAGE_WIDTH, IMAGE_HEIGHT);
    }
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutKeyboardFunc (keyboard);
    glutIdleFunc(spinDisplay);
    glutMainLoop();

    //dc1394_stop_iso_transmission(handle,camera.node);
    dc1394_dma_unlisten(handle,&camera);
    dc1394_dma_release_camera(handle,&camera);
    raw1394_destroy_handle(handle);

    return 0;
}
