////////////////////////////////////////////////////////
//
// 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_video.h"

#include "Base/GemCache.h"

CPPEXTERN_NEW(pix_video)

/////////////////////////////////////////////////////////
//
// video
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
pix_video :: pix_video()
    	   : m_haveVideo(0), m_swap(1), m_colorSwap(0),
			 m_hWndC(NULL)
{
    m_pixBlock.image.data = NULL;
    
    // Connect to the daemon
    post("Unable to open video connection");
}

/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
pix_video :: ~pix_video()
{
    stopTransfer();

    // Clean up the video
    if (m_haveVideo)
    {
    	post("Closed video connection");
    }
    cleanPixBlock();
}

/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void pix_video :: render(GemState *state)
{
    if (!m_haveVideo)
    {
		post("unable to activate video");
		return;
    }

    m_pixBlock.newimage = 1;
    state->image = &m_pixBlock;
}

/////////////////////////////////////////////////////////
// startRendering
//
/////////////////////////////////////////////////////////
void pix_video :: startRendering()
{
    m_pixBlock.newimage = 1;
}

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

/////////////////////////////////////////////////////////
// startTransfer
//
/////////////////////////////////////////////////////////
int pix_video :: startTransfer()
{
    if (!m_haveVideo) return(0);
	return(1);
}

/////////////////////////////////////////////////////////
// stopTransfer
//
/////////////////////////////////////////////////////////
int pix_video :: stopTransfer()
{
    if ( !m_haveVideo ) return(0);

    // Clean up the buffer
    
    return(1);
}

/////////////////////////////////////////////////////////
// offsetMess
//
/////////////////////////////////////////////////////////
void pix_video :: offsetMess(int x, int y)
{
    if (!m_haveVideo)
    {
    	post("Connect to video first");
    	return;
    }
    
    // stop the transfer and destroy the buffer
    if ( !stopTransfer() ) 
    {
    	post("Video: error stopping transfer");
    	return;
    }

    // start the transfer and rebuild the buffer
    if ( !startTransfer() ) 
    {
    	post("Video: error starting transfer");
    	return;
    }
}

/////////////////////////////////////////////////////////
// dimenMess
//
/////////////////////////////////////////////////////////
void pix_video :: dimenMess(int x, int y)
{
    if (!m_haveVideo)
    {
    	post("Connect to video first");
    	return;
    }
    
    // stop the transfer and destroy the buffer
    if ( !stopTransfer() ) 
    {
    	post("Video: error stopping transfer");
    	return;
    }

    m_pixBlock.image.xsize = x;
    m_pixBlock.image.ysize = y;;

    cleanPixBlock();
    int dataSize = m_pixBlock.image.xsize * m_pixBlock.image.ysize
    	    	    * 4 * sizeof(unsigned char);
    m_pixBlock.image.data = new unsigned char[dataSize];

    // start the transfer and rebuild the buffer
    if ( !startTransfer() ) 
    {
    	post("Video: error starting transfer");
    	return;
    }
}

/////////////////////////////////////////////////////////
// cleanPixBlock
//
/////////////////////////////////////////////////////////
void pix_video :: cleanPixBlock()
{
    delete [] m_pixBlock.image.data;
    m_pixBlock.image.data = NULL;
}

/////////////////////////////////////////////////////////
// swapMess
//
/////////////////////////////////////////////////////////
void pix_video :: swapMess(int state)
{
    if (state) m_swap = 1;
    else m_swap = 0;
}

/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void pix_video :: obj_setupCallback(t_class *classPtr)
{
    class_addmethod(classPtr, (t_method)&pix_video::dimenMessCallback,
    	    gensym("dimen"), A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&pix_video::offsetMessCallback,
    	    gensym("offset"), A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&pix_video::swapMessCallback,
    	    gensym("swap"), A_FLOAT, A_NULL);
}
void pix_video :: dimenMessCallback(void *data, t_floatarg x, t_floatarg y)
{
    GetMyClass(data)->dimenMess(x, y);
}
void pix_video :: offsetMessCallback(void *data, t_floatarg x, t_floatarg y)
{
    GetMyClass(data)->offsetMess(x, y);
}
void pix_video :: swapMessCallback(void *data, t_floatarg state)
{
    GetMyClass(data)->swapMess(state);
}
