#include "ofCvColorImage.h"
#include "ofCvGrayscaleImage.h"
#include "ofCvFloatImage.h"

//-------------------------------------------------------------------------------------
ofCvColorImage::ofCvColorImage()
{
	bAllocated = false;
	width = height = 0;
}

//-------------------------------------------------------------------------------------
ofCvColorImage::ofCvColorImage(int _w, int _h)
{
	bAllocated = false;
	allocate(_w, _h);
}

//-------------------------------------------------------------------------------------
ofCvColorImage::~ofCvColorImage()
{
	clear();
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::allocate(int _w, int _h){
	if (!bAllocated)
	{
		cvImage 			= cvCreateImage(cvSize(_w,_h), IPL_DEPTH_8U, 3);
		cvImageTemp			= cvCreateImage(cvSize(_w,_h), IPL_DEPTH_8U, 3);
		cvImageGray			= cvCreateImage(cvSize(_w,_h), IPL_DEPTH_8U, 1);
		pixels 				= new unsigned char[_w*_h * 3];
		width 				= _w;
		height 				= _h;
		tex.allocate(width, height, GL_RGB);
		bAllocated			= true;
	}
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::clear(){
	if (bAllocated)
	{
		cvReleaseImage(&cvImage);
		cvReleaseImage(&cvImageTemp);
		cvReleaseImage(&cvImageGray);
		delete [] pixels;
		width				= 0;
		height				= 0;;
		tex.clear();
		bAllocated			= false;
	}
}

// ---------------------------------
void ofCvColorImage::set(int value){
	cvSet(cvImage, cvScalar(value, value, value));
}

// ---------------------------------
void ofCvColorImage::set(int r, int g, int b){
	cvSet(cvImage, cvScalar(r, g, b));
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::setFromGrayscaleImage(ofCvGrayscaleImage& mom){
	cvCvtColor( mom.getCvImage() ,cvImage, CV_GRAY2RGB); 
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::setFromFloatImage(ofCvFloatImage& mom){
	cvConvertScale( mom.getCvImage(), cvImageGray, 1, 0);
	cvCvtColor( cvImageGray ,cvImage, CV_GRAY2RGB); 
}

// ---------------------------------
void ofCvColorImage::warpIntoMe(ofCvColorImage mom, ofCvPoint2f src[4], ofCvPoint2f dst[4]){
	// compute matrix for perspectival warping (homography)
	CvPoint2D32f cvsrc[4];
	CvPoint2D32f cvdst[4];
	CvMat *translate = cvCreateMat(3,3,CV_32FC1);
	cvSetZero(translate);
	for (int i = 0; i < 4; i++){
		cvsrc[i].x = src[i].x;
		cvsrc[i].y = src[i].y;
		cvdst[i].x = dst[i].x;
		cvdst[i].y = dst[i].y;
	}
	cvWarpPerspectiveQMatrix(cvsrc, cvdst, translate);  // calculate homography
	cvWarpPerspective( mom.getCvImage(), cvImage, translate);
	cvReleaseMat(&translate);
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::setFromPixels(unsigned char * _pixels, int w, int h){
	for (int i = 0; i < h; i++){
		memcpy(cvImage->imageData + (i * cvImage->widthStep), _pixels + (i * w * 3), w*3);
	}
	for (int i = 0; i < h; i++){
		memcpy(pixels + (i * w * 3), cvImage->imageData + (i * cvImage->widthStep), w*3);
	}
}

//-------------------------------------------------------------------------------------
unsigned char * ofCvColorImage::getPixels(){
	// copy each line of pixels:
	for (int i = 0; i < height; i++){
		memcpy(pixels + (i * width * 3), cvImage->imageData + (i * cvImage->widthStep), width*3);
	}
	return pixels;
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::swapTemp(){
	IplImage * temp;
	temp 			= cvImage;
	cvImage 		= cvImageTemp;
	cvImageTemp 	= temp;
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::draw(float x, float y){

	// note, this is a bit ineficient, as we have to
	// copy the data out of the cvImage into the pixel array
	// and then upload to texture.  We should add
	// to the texture class an override for pixelstorei
	// that allows stepped-width image upload:

	tex.loadData(getPixels(), width, height, GL_RGB);
	tex.draw(x,y,width, height);
}
void ofCvColorImage::draw(float x, float y, float w, float h){

	// note, this is a bit ineficient, as we have to
	// copy the data out of the cvImage into the pixel array
	// and then upload to texture.  We should add
	// to the texture class an override for pixelstorei
	// that allows stepped-width image upload:

	tex.loadData(getPixels(), width, height, GL_RGB);
	tex.draw(x,y,w,h);
}


//-------------------------------------------------------------------------------------
void ofCvColorImage::operator =	( ofCvColorImage & mom ){
	if (mom.width == width && mom.height == height){
		cvCopy(mom.getCvImage(), cvImage, 0);
	} else {
		// what do we do?
		// cvResize?
		// cvClone?
		printf("error in =, images are different sizes\n");
	}
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::operator *=	(  ofCvColorImage & mom ){
	if (mom.width == width && mom.height == height){
		float scalef = 1.0f / 255.0f;
		cvMul(cvImage, mom.getCvImage(), cvImageTemp, scalef);
		swapTemp();
	} else {
		// what do we do?
		// cvResize?
		// cvClone?
		printf("error in =, images are different sizes\n");
	}
}

//-------------------------------------------------------------------------------------
void ofCvColorImage::operator +=	(  ofCvColorImage & mom ){
	if (mom.width == width && mom.height == height){
		cvAdd(cvImage, mom.getCvImage(), cvImageTemp);
		swapTemp();
	} else {
		// what do we do?
		// cvResize?
		// cvClone?
		printf("error in =, images are different sizes\n");
	}
}


//-------------------------------------------------------------------------------------
void ofCvColorImage::operator -=	(  ofCvColorImage & mom ){
	if (mom.width == width && mom.height == height){
		cvSub(cvImage, mom.getCvImage(), cvImageTemp);
		swapTemp();
	} else {
		// what do we do?
		// cvResize?
		// cvClone?
		printf("error in =, images are different sizes\n");
	}
}