/*
 * HACKED ON BY FT... a lot. ;)
 */

/*
 * based on code by Yuan-Chu Tai http://www.geocities.com/chobitsfan/
 */

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

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


//big buffer
static GLubyte dataout[512][512][3];

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

static GLenum errCode;
const GLubyte *errString;

//more resolution, slower display. 
#define TEX_WIDTH 128
#define TEX_HEIGHT  128

#define IMAGE_WIDTH 640
#define IMAGE_HEIGHT 480

#define ROT90 0

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);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_WIDTH,
            TEX_HEIGHT, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
            dataout);
    if ((errCode = glGetError()) != GL_NO_ERROR) {
        errString = gluErrorString(errCode);
        fprintf (stderr, "OpenGL Error: %s\n", errString);
    }


}

void display(void)
{

    dc1394_dma_single_capture(&camera); //grab a frame

    //gluScaleImage(GL_RGB, 640, 480, GL_UNSIGNED_BYTE,
    //        camera.capture_buffer, TEX_WIDTH, TEX_HEIGHT, 
    //		GL_UNSIGNED_BYTE, dataout);
    gluScaleImage(GL_LUMINANCE, IMAGE_WIDTH, IMAGE_HEIGHT, GL_UNSIGNED_BYTE,
            camera.capture_buffer, TEX_WIDTH, TEX_HEIGHT, 
            GL_UNSIGNED_BYTE, dataout);

    dc1394_dma_done_with_buffer(&camera);	

    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_WIDTH,
            TEX_HEIGHT, GL_LUMINANCE, GL_UNSIGNED_BYTE,
            dataout);


    //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(0.0, 1.0, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f(1.0, 1.0, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex3f(1.0, 0.0, 0.0);
    glEnd();

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


}

void reshape(int w, int h)
{
    glViewport(0,0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, 1, 1, 0, -1, 1);

    //you can do whatever you want here... it's not drawpixel

    //glRotated(180, 0,0,1 );
    //glTranslatef(-1,-1,0);
    if (ROT90) {
        glRotated(90, 0,0,1 );
        glTranslatef(0,-1,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 | GLUT_DEPTH);
    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;
}

