////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// mdanks@cybermed.ucsd.edu
//
// Implementation file
//
//    Copyright (c) 1997-1998 Mark Danks.
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "pix_snap.h"

#include "Base/GemMan.h"
#include "Base/GemCache.h"

CPPEXTERN_NEW(pix_snap)

/////////////////////////////////////////////////////////
//
// pix_snap
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
pix_snap :: pix_snap()
    	  : m_originalImage(NULL),
    	    m_x(0), m_y(0), m_width(-1), m_height(-1)
{
    inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("list"), gensym("vert_size"));
    inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("list"), gensym("vert_pos"));
}

/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
pix_snap :: ~pix_snap()
{
    cleanImage();
}

/////////////////////////////////////////////////////////
// snapMess
//
/////////////////////////////////////////////////////////
void pix_snap :: snapMess()
{
    cleanImage();

    if ( !GemMan::windowExists() ) return;
        
    // check about the max size of the window    
    int real_width, real_height;
    if (m_width < 0)
    {
    	real_width = GemMan::m_width;
    	m_x = 0;
    }
    else
    {
    	if ( m_width + m_x > GemMan::m_width ) m_width = GemMan::m_width - m_x;
    	real_width = m_width;
    }
    
    if (m_height < 0)
    {
    	real_height = GemMan::m_height;
    	m_y = 0;
    }
    else
    {
    	if ( m_height + m_y > GemMan::m_height ) m_height = GemMan::m_height - m_y;
    	real_height = m_height;
    }
    
    m_originalImage = new imageStruct;
    m_originalImage->xsize = real_width;
    m_originalImage->ysize = real_height;
    m_originalImage->csize = 4;
    m_originalImage->type  = GL_UNSIGNED_BYTE;
    m_originalImage->format = GL_RGBA;
    m_originalImage->data = new
    	unsigned char[m_originalImage->xsize * m_originalImage->ysize * m_originalImage->csize];
    
    glReadPixels(m_x, m_y, real_width, real_height,
    	    	 m_originalImage->format, m_originalImage->type, m_originalImage->data);    
    
       
    post("snapped image"); 
}

/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void pix_snap :: render(GemState *state)
{
    // if we don't have an image, just return
    if (!m_originalImage) return;
    
    // do we need to reload the image?    
    if (m_cache->resendImage)
    {
	refreshImage(&(m_pixBlock.image), m_originalImage);
    	m_pixBlock.newimage = 1;
    	m_cache->resendImage = 0;
    }
    
    state->image = &m_pixBlock;
}

/////////////////////////////////////////////////////////
// postrender
//
/////////////////////////////////////////////////////////
void pix_snap :: postrender(GemState *state)
{
    m_pixBlock.newimage = 0;
    state->image = NULL;
}

/////////////////////////////////////////////////////////
// sizeMess
//
/////////////////////////////////////////////////////////
void pix_snap :: sizeMess(int width, int height)
{
    m_width = width;
    m_height = height;
}

/////////////////////////////////////////////////////////
// posMess
//
/////////////////////////////////////////////////////////
void pix_snap :: posMess(int x, int y)
{
    m_x = x;
    m_y = y;
}

/////////////////////////////////////////////////////////
// cleanImage
//
/////////////////////////////////////////////////////////
void pix_snap :: cleanImage()
{
    // release previous data
    if (m_originalImage)
    {
	delete [] m_originalImage->data;
	delete m_originalImage;
	m_originalImage = NULL;

    	delete [] m_pixBlock.image.data;
    }
}

/////////////////////////////////////////////////////////
// static member functions
//
/////////////////////////////////////////////////////////
void pix_snap :: obj_setupCallback(t_class *classPtr)
{
    class_addmethod(classPtr, (t_method)&pix_snap::snapMessCallback,
    	    gensym("snap"), A_NULL);

    class_addmethod(classPtr, (t_method)&pix_snap::sizeMessCallback,
    	    gensym("vert_size"), A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&pix_snap::posMessCallback,
    	    gensym("vert_pos"), A_FLOAT, A_FLOAT, A_NULL);
}
void pix_snap :: snapMessCallback(void *data)
{
    GetMyClass(data)->snapMess();
}
void pix_snap :: sizeMessCallback(void *data, t_floatarg width, t_floatarg height)
{
    GetMyClass(data)->sizeMess((int)width, (int)height);
}
void pix_snap :: posMessCallback(void *data, t_floatarg x, t_floatarg y)
{
    GetMyClass(data)->posMess((int)x, (int)y);
}
