/*
==================
Transformations before drawing a primitive
==================
*/
void DirectXRender::setForPrimitive(BYTE pA) {
	// Transformation
	setTransform2d(0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0);

	// Antialiasing
	//if (_antialiasing)
	//{
	//  exit (0);
	//SetRainbow (IND_ALPHA, 255, 255, 255, pA, 0, 0, 0, 255, 0, 0);
	//}
	//else
	//{

	//IF - Totally opaque
	if (pA == 255) {
		setRainbow2d(IND_OPAQUE, 1, 0, 0, IND_FILTER_POINT, 255, 255, 255, pA, 0, 0, 0, 255, 0, 0);
	} else { // ELSE - Some transparency
		setRainbow2d(IND_ALPHA, 1, 0, 0, IND_FILTER_POINT, 255, 255, 255, pA, 0, 0, 0, 255, 0, 0);
	}
	//}

	// Disable color OP
	_info._device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);

	// Pixel format
	_info._device->SetFVF(D3DFVF_PIXEL);
}
void OpenGLRender::setForPrimitive(BYTE pA, bool pResetTransform) {
	// Transformation reset
	if (pResetTransform) {
		setTransform2d(0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0);
	}

	//IF - Totally opaque
	if (pA == 255) {
		setRainbow2d(IND_OPAQUE, 1, 0, 0, IND_FILTER_POINT, 255, 255, 255, pA, 0, 0, 0, 255, 0, 0);
	} else { // ELSE - Some transparency
		setRainbow2d(IND_ALPHA, 1, 0, 0, IND_FILTER_POINT, 255, 255, 255, pA, 0, 0, 0, 255, 0, 0);
	}
}
/*
==================
Blits a bounding line
==================
*/
void DirectXRender::BlitGridLine(int pPosX1, int pPosY1, int pPosX2, int pPosY2,  BYTE pR, BYTE pG, BYTE pB, BYTE pA, D3DXMATRIX pWorldMatrix) {
	setTransform2d(0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0);

	// Untransformed Points
	D3DXVECTOR2 mP1Untransformed((float) pPosX1, (float) pPosY1);
	D3DXVECTOR2 mP2Untransformed((float) pPosX2, (float) pPosY2);

	D3DXVECTOR4 mP1, mP2;
	D3DXVec2Transform(&mP1, &mP1Untransformed, &pWorldMatrix);
	D3DXVec2Transform(&mP2, &mP2Untransformed, &pWorldMatrix);

	// Color
	setRainbow2d(IND_OPAQUE, 1, 0, 0, IND_FILTER_POINT, pR, pG, pB, pA, 0, 0, 0, 255, 0, 0);

	// Color
	_info._device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);

	// Pixel format
	_info._device->SetFVF(D3DFVF_PIXEL);

	// Filling pixels
	fillPixel(&_pixels [0], (int) mP1.x, (int) mP1.y, pR, pG, pB);
	fillPixel(&_pixels [1], (int) mP2.x, (int) mP2.y, pR, pG, pB);

	// Blitting line
	_info._device->DrawPrimitiveUP(D3DPT_LINESTRIP, 1, &_pixels, sizeof(PIXEL));
}
/*
==================
Blits a bounding line
==================
*/
 void OpenGLRender::blitGridLine (int pPosX1, int pPosY1, int pPosX2, int pPosY2,  BYTE pR, BYTE pG, BYTE pB, BYTE pA)
{	
	float r(static_cast<float>(pR) / 255.0f), g(static_cast<float>(pG) / 255.0f), b(static_cast<float>(pB) / 255.0f), a(static_cast<float>(pA) / 255.0f);
	// Filling pixels
    fillPixel (&_pixels[0], static_cast<float>(pPosX1), static_cast<float>(pPosY1), r, g, b, a);
    fillPixel (&_pixels[1], static_cast<float>(pPosX2), static_cast<float>(pPosY2), r, g, b, a);

	//Render primitive - No textures
	glDisable(GL_TEXTURE_2D);
	// Color settings
    setRainbow2d (IND_OPAQUE, 1, 0, 0, IND_FILTER_POINT, pR, pG, pB, pA, 0, 0, 0, 255, 0, 0);

	//Blitting
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);

	//Polygon blitting
	glVertexPointer(3, GL_FLOAT, sizeof(PIXEL), &_pixels[0]._x);
	glColorPointer(4, GL_FLOAT, sizeof(PIXEL), &_pixels[0]._colorR);
	glDrawArrays(GL_LINE_STRIP, 0, 2);

#ifdef _DEBUG
    GLenum glerror = glGetError();
	if (glerror) {
		g_debug->header("OpenGL error in grid line blitting ", 2);
	}
#endif
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);	
}
/*
==================
Blits a bounding line
==================
*/
 void OpenGLRender::blitGridLine (int pPosX1, int pPosY1, int pPosX2, int pPosY2,  unsigned char pR, unsigned char pG, unsigned char pB, unsigned char pA)
{	
	float r(static_cast<float>(pR) / 255.0f), g(static_cast<float>(pG) / 255.0f), b(static_cast<float>(pB) / 255.0f), a(static_cast<float>(pA) / 255.0f);
	// Filling pixels
    fillPixel (&_pixels[0], static_cast<float>(pPosX1), static_cast<float>(pPosY1), r, g, b, a);
    fillPixel (&_pixels[1], static_cast<float>(pPosX2), static_cast<float>(pPosY2), r, g, b, a);

	//Render primitive - No textures
	setGLClientStateToPrimitive();
    
	// Color settings
    setRainbow2d (IND_OPAQUE, 1, 0, 0, IND_FILTER_POINT, pR, pG, pB, pA, 0, 0, 0, 255, 0, 0);

	//Polygon blitting
	glVertexPointer(3, GL_FLOAT, sizeof(PIXEL), &_pixels[0]._x);
	glColorPointer(4, GL_FLOAT, sizeof(PIXEL), &_pixels[0]._colorR);
	glDrawArrays(GL_LINE_STRIP, 0, 2);

#ifdef _DEBUG
    GLenum glerror = glGetError();
	if (glerror) {
		g_debug->header("OpenGL error in grid line blitting ", DebugApi::LogHeaderError);
	}
#endif

    //Reenable texturing
	setGLClientStateToTexturing();
}
/*
==================
Blits a bounding circle area
==================
*/
void OpenGLRender::blitCollisionCircle(int pPosX, int pPosY, int pRadius, float pScale,  BYTE pR, BYTE pG, BYTE pB, BYTE pA, IND_Matrix pIndWorldMatrix) {
	float r(static_cast<float>(pR) / 255.0f), g(static_cast<float>(pG) / 255.0f), b(static_cast<float>(pB) / 255.0f), a(static_cast<float>(pA) / 255.0f);

	// Filling pixels
	float x (0.0f);
	float y (0.0f);
	int points (SIDES_PER_CIRCLE + 1);
	assert(0 != points);
	float angle (2*PI / SIDES_PER_CIRCLE);
	for (int i = 0; i <= points ; i++) {
		x = pPosX + (pRadius * cosf(angle*i));
		y = pPosY + (pRadius * sinf(angle*i));
		fillPixel (&_pixels[i], x, y, r, g, b, a);
	}
    
	//Render primitive - No textures
	glDisable(GL_TEXTURE_2D);
	//Transform
	setTransform2d(pIndWorldMatrix);

	// Color settings
    setRainbow2d (IND_OPAQUE, 1, 0, 0, IND_FILTER_POINT, pR, pG, pB, pA, 0, 0, 0, 255, 0, 0);

	//Blitting
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);

	//Polygon blitting
	glVertexPointer(3, GL_FLOAT, sizeof(PIXEL), &_pixels[0]._x);
	glColorPointer(4, GL_FLOAT, sizeof(PIXEL), &_pixels[0]._colorR);
	glDrawArrays(GL_LINE_STRIP, 0, points);

#ifdef _DEBUG
    GLenum glerror = glGetError();
	if (glerror) {
		g_debug->header("OpenGL error in circle blitting ", 2);
	}
#endif
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);	

}
/*
==================
Blits a bounding line
==================
*/
void DirectXRender::blitCollisionLine(int pPosX1, int pPosY1, int pPosX2, int pPosY2,  BYTE pR, BYTE pG, BYTE pB, BYTE pA, IND_Matrix pIndWorldMatrix) {
	setTransform2d(0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0);

	IND_Vector3 mP1 (static_cast<float>(pPosX1),static_cast<float>(pPosY1),0.0f);
	IND_Vector3 mP2 (static_cast<float>(pPosX2),static_cast<float>(pPosY2),0.0f);
	_math->transformVector3DbyMatrix4D(mP1,pIndWorldMatrix);
	_math->transformVector3DbyMatrix4D(mP2,pIndWorldMatrix);

	// Color
	setRainbow2d(IND_OPAQUE, 1, 0, 0, IND_FILTER_POINT, pR, pG, pB, pA, 0, 0, 0, 255, 0, 0);

	// Color
	_info._device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);

	// Pixel format
	_info._device->SetFVF(D3DFVF_PIXEL);

	// Filling pixels
	fillPixel(&_pixels [0], (int) mP1._x, (int) mP1._y, pR, pG, pB);
	fillPixel(&_pixels [1], (int) mP2._x, (int) mP2._y, pR, pG, pB);

	// Blitting line
	_info._device->DrawPrimitiveUP(D3DPT_LINESTRIP, 1, &_pixels, sizeof(PIXEL));
}
/*
==================
Blits a bounding circle area
==================
*/
void DirectXRender::blitCollisionCircle(int pPosX, int pPosY, int pRadius, float pScale,  BYTE pR, BYTE pG, BYTE pB, BYTE pA, IND_Matrix pIndWorldMatrix) {
	if (pScale != 1.0f) pRadius = (int)(pRadius * pScale);

	setTransform2d(0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0);


	IND_Vector3 mP1 (static_cast<float>(pPosX),static_cast<float>(pPosY),0.0f);
	_math->transformVector3DbyMatrix4D(mP1,pIndWorldMatrix);

	// Color
	setRainbow2d(IND_OPAQUE, 1, 0, 0, IND_FILTER_POINT, pR, pG, pB, pA, 0, 0, 0, 255, 0, 0);

	// Color
	_info._device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);

	// Pixel format
	_info._device->SetFVF(D3DFVF_PIXEL);

	// Blitting
	int x, y, i;
	float c = 2 * (float)(PI / SIDES_PER_CIRCLE);
	int points (SIDES_PER_CIRCLE + 1);
	assert (0 != points);
	for (i = 0; i <= points; i++) {
		
		x = (int)(mP1._x + (pRadius * cos((i * c) + D3DXToRadian(0))));
		y = (int)(mP1._y + (pRadius * sin((i* c) + D3DXToRadian(0))));

		fillPixel(&_pixels [i], x, y, pR, pG, pB);
	}

	fillPixel(&_pixels [i], (int) mP1._x + (int)(pRadius * cos(D3DXToRadian(0))), (int) mP1._y + (int)(pRadius * sin(D3DXToRadian(0))), pR, pG, pB);

	// Blitting circle
	_info._device->DrawPrimitiveUP(D3DPT_LINESTRIP, points, &_pixels, sizeof(PIXEL));
}
void DirectXRender::blitText(IND_Font *pFo,
                             char *pText,
                             int pX,
                             int pY,
                             int pOffset,
                             int pLineSpacing,
                             float pScaleX,
                             float pScaleY,
                             unsigned char pR,
                             unsigned char pG,
                             unsigned char pB,
                             unsigned char pA,
                             unsigned char pFadeR,
                             unsigned char pFadeG,
                             unsigned char pFadeB,
                             unsigned char pFadeA,
                             IND_Filter pLinearFilter,
                             IND_BlendingType pSo,
                             IND_BlendingType pDs,
                             IND_Align pAlign) {
	// ----- Transform -----

	bool correctParams = true;
	if(!pFo->getSurface()) {
		correctParams = false;
	}

	if (correctParams) {
		//SetTransform2d (pX, pY, 0, 0, 0, 1, 1, 0, 0, 0, 0, pFo->getSurface()->getWidthBlock(), pFo->getSurface()->getHeightBlock(), 0);
		setTransform2d(pX, pY, 0, 0, 0, pScaleX, pScaleY, 0, 0, 0, 0, pFo->getSurface()->getWidthBlock(), pFo->getSurface()->getHeightBlock(), 0);
		setRainbow2d(pFo->_font._surface->getTypeInt(), 1, 0, 0, pLinearFilter, pR, pG, pB, pA, pFadeR, pFadeG, pFadeB, pFadeA, pSo, pDs);

		// ----- Drawing text   -----

		unsigned char mChar1;
		unsigned char mChar2;
		int mCont1 = 0;
		int mCont2 = 0;
		int mTranslationX = 0;
		int mTranslationY = 0;
		bool mErrorChar;    // Char that doesn't exist
		int mSentencePos;
		int mLongActualSentence;

		D3DXMATRIX mMatTraslation, mMatWorld, mMatWorldOriginal;
		_info._device->GetTransform(D3DTS_WORLD, &mMatWorld);
		_info._device->GetTransform(D3DTS_WORLD, &mMatWorldOriginal);

		mCont1 = 0;
		mChar1 = pText [mCont1++];

		while (mChar1 != 0) {
			// If it's a new line or it's the first line
			if (mChar1 == '\n' || mCont1 == 1) {
				// First line
				if (mCont1 == 1)
					mSentencePos = 0;
				else
					mSentencePos = mCont1;

				// Set the alignment
				switch (pAlign) {
				case IND_CENTER: {
					//mLongActualSentence = GetLongInPixels (pFo, pText, mSentencePos, pOffset);
					mLongActualSentence = static_cast<int>(getLongInPixels(pFo, pText, mSentencePos, pOffset) * pScaleX);
					mTranslationX = (int)(mLongActualSentence / 2);
					break;
				}

				case IND_RIGHT: {
					//mLongActualSentence = GetLongInPixels (pFo, pText, mSentencePos, pOffset);
					mLongActualSentence = static_cast<int>(getLongInPixels(pFo, pText, mSentencePos, pOffset) * pScaleX);
					mTranslationX = (int)(mLongActualSentence);

					break;
				}

				case IND_LEFT: {
					break;
				}
				}

				D3DXMatrixTranslation(&mMatTraslation, (float) - mTranslationX, (float) mTranslationY, 0);
				//mTranslationY += (pLineSpacing);
				mTranslationY += static_cast<int>((pLineSpacing * pScaleY));
				D3DXMatrixMultiply(&mMatWorld, &mMatWorldOriginal, &mMatTraslation);
				_info._device->SetTransform(D3DTS_WORLD, &mMatWorld);
			}

			// It's a normal character
			if (mChar1 != '\n') {

				mErrorChar = 0;
				mCont2 = 0;
				mChar2 = pFo->getLetters() [mCont2++]._letter;

				// Seek its location in the bitmap
				while (mChar2 != mChar1 && mCont2 < pFo->getNumChars()) mChar2 = pFo->getLetters() [mCont2++]._letter;
				if (mCont2  ==  pFo->getNumChars())
					mErrorChar = 1;

				mCont2--;
				if (!mErrorChar) {
					blitRegionSurface(pFo->getSurface(),
									  pFo->getLetters() [mCont2]._offsetX + 1,
									  pFo->getLetters() [mCont2]._offsetY + 1,
									  pFo->getLetters() [mCont2]._widthChar - 1,
									  pFo->getLetters() [mCont2]._heightChar - 1);
				}


				// Displacement of the character
				//SetTranslation ((pFo->getLetters() [mCont2]._widthChar) + pOffset, 0, &mMatWorld, &mMatTraslation);
				SetTranslation(static_cast<int>(((pFo->getLetters() [mCont2]._widthChar) + pOffset) * pScaleX), 0, &mMatWorld, &mMatTraslation);
			}

			// Advance one character
			mChar1 = pText [mCont1++];
		}
	}
}
void OpenGLRender::blitText(IND_Font *pFo,
                            char *pText,
                            int pX,
                            int pY,
                            int pOffset,
                            int pLineSpacing,
                            float pScaleX,
                            float pScaleY,
                            BYTE pR,
                            BYTE pG,
                            BYTE pB,
                            BYTE pA,
                            BYTE pFadeR,
                            BYTE pFadeG,
                            BYTE pFadeB,
                            BYTE pFadeA,
                            IND_Filter pLinearFilter,
                            IND_BlendingType pSo,
                            IND_BlendingType pDs,
                            IND_Align pAlign) {
	// ----- Transform -----
	bool correctParams = true;
	if(!pFo->getSurface()) {
		correctParams = false;
	}

	if (correctParams) {
		setTransform2d(pX, pY, 0, 0, 0, pScaleX, pScaleY, 0, 0, 0, 0, pFo->getSurface()->getWidthBlock(), pFo->getSurface()->getHeightBlock(), 0);
		setRainbow2d(pFo->_font._surface->getTypeInt(), 1, 0, 0, pLinearFilter, pR, pG, pB, pA, pFadeR, pFadeG, pFadeB, pFadeA, pSo, pDs);

		// ----- Drawing text   -----
		
		BYTE mChar1;
		BYTE mChar2;
		int mCont1 = 0;
		int mCont2 = 0;
		int mTranslationX = 0;
		int mTranslationY = 0;
		bool mErrorChar;    // Char that doesn't exist
		int mSentencePos;
		int mLongActualSentence;
		GLfloat mLineTransform[16];  //Maintains a transform inside the entity coord system
		GLfloat mEntityTransform[16]; //Maintains transform for the whole entity coord system
		mCont1 = 0;
		mChar1 = pText [mCont1++];

		//Store entity transform
		glGetFloatv(GL_MODELVIEW_MATRIX,mEntityTransform);

		//LOOP - Blit character by character
		while (mChar1 != 0) {
			// If it's a new line or it's the first line
			if (mChar1 == '\n' || mCont1 == 1) {
				// First line
				if (mCont1 == 1) {
					mSentencePos = 0;
				//Any other line
				} else {
					mSentencePos = mCont1;
				}

				// Set the alignment
				switch (pAlign) {
					case IND_CENTER: {
						mLongActualSentence = static_cast<int>(getLongInPixels(pFo, pText, mSentencePos, pOffset) * pScaleX);
						mTranslationX = (int)(mLongActualSentence / 2);
						break;
					}

					case IND_RIGHT: {
						mLongActualSentence = static_cast<int>(getLongInPixels(pFo, pText, mSentencePos, pOffset) * pScaleX);
						mTranslationX = (int)(mLongActualSentence);

						break;
					}

					case IND_LEFT: {
						break;
					}
				}

				//Load line transform matrix taking into account entity transform
				//This effectively resets transform to first character in the new line
				IND_Matrix transform;
				_math.matrix4DSetTranslation(transform, static_cast<float>(-mTranslationX), static_cast<float>(mTranslationY), 0.0f);
				transform.arrayRepresentation(mLineTransform);
				glLoadMatrixf(mEntityTransform);
				glMultMatrixf(mLineTransform);
				mTranslationY += static_cast<int>((pLineSpacing * pScaleY));
			} //Was first new line or first line

			// It's a normal character
			if (mChar1 != '\n') {

				mErrorChar = 0;
				mCont2 = 0;
				mChar2 = pFo->getLetters() [mCont2++]._letter;

				// Seek its location in the bitmap
				while (mChar2 != mChar1 && mCont2 < pFo->getNumChars()) {
					mChar2 = pFo->getLetters() [mCont2++]._letter;
				}
				if (mCont2  ==  pFo->getNumChars())
					mErrorChar = 1;

				mCont2--;
				if (!mErrorChar) {
//#warning lookout
					//mvTransformPresetState();  //Need to preset transform state, as the blit operation will reset the state!!!!
					blitRegionSurface(pFo->getSurface(),
									  pFo->getLetters() [mCont2]._offsetX + 1,
									  pFo->getLetters() [mCont2]._offsetY + 1,
									  pFo->getLetters() [mCont2]._widthChar - 1,
									  pFo->getLetters() [mCont2]._heightChar - 1);
				}

				//Displacement of the character.
				//Displacement transform accumulates for every character in the line
				float charTranslateX = ((pFo->getLetters() [mCont2]._widthChar) + pOffset) * pScaleX;
				glTranslatef(charTranslateX,0.0f,0.0f);
			}//Was normal character

			// Advance one character
			mChar1 = pText [mCont1++];
		}//LOOP END - Blit character by character

	}
}