//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "ThreeDImageViewer_Form.h"
#include "MultiLanguage.h"
#include "Environment.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "TntExtCtrls"
#pragma link "TntStdCtrls"
#pragma resource "*.dfm"
TThreeDImageViewerForm *ThreeDImageViewerForm;
typedef enum {
	RESERVED, TABLET, DEFECT_AREA,
} DisplayLists;

#define MIN_ROTATE_Y_ANGLE		-10		// in degree
#define MAX_ROTATE_Y_ANGLE      15
//#define MIN_ROTATE_Y_ANGLE		-30		// in degree
//#define MAX_ROTATE_Y_ANGLE      30
//---------------------------------------------------------------------------
__fastcall TThreeDImageViewerForm::TThreeDImageViewerForm(TComponent* Owner)
	: TTntForm(Owner)
{
  if(DefaultLCID == 1028 || DefaultLCID == 2052 || DefaultLCID == 3076 || DefaultLCID == 4100)
    ComponentSetFontName(this, "SimSun");

  CloseButton->Caption = THREEDIMAGEVIEWERFORM_BUTTON_CAPTION_01;
  DefectAreaButton->Caption = THREEDIMAGEVIEWERFORM_BUTTON_CAPTION_02;
  PositionResetButton->Caption = THREEDIMAGEVIEWERFORM_BUTTON_CAPTION_03;
  this->Caption = THREEDIMAGEVIEWERFORM_FORM_CAPTION_01;

	ShowDefectArea = true;
//	this->DoubleBuffered = true;
}
//---------------------------------------------------------------------------
void __fastcall TThreeDImageViewerForm::CloseButtonClick(TObject *Sender)
{
	this->Close();	
}
//---------------------------------------------------------------------------
void __fastcall TThreeDImageViewerForm::FormCreate(TObject *Sender)
{
	GLfloat lightColor0[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
	GLfloat lightColor1[] = {0.08, 0.1, 0.08, 1.0}; /* green-tinted */


//	ThreeDImage->Picture->Bitmap->Height = ThreeDImage->Height;
//	ThreeDImage->Picture->Bitmap->Width = ThreeDImage->Width;
//	ThreeDImage->Picture->Bitmap->PixelFormat = pf24bit;
	GHDC = GetDC(ImagePanel->Handle);
//	GHDC = GetDC(Handle);
//	GHDC = ThreeDImage->Canvas->Handle;
	if (!SetupPixelFormat(GHDC)) Close();
	GLRC = wglCreateContext(GHDC);
	wglMakeCurrent(GHDC, GLRC);

	glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);
	glMatrixMode(GL_PROJECTION);
	gluPerspective( /* field of view in degree */ 40.0,
  /* aspect ratio */ 1.0,
	/* Z near */ 1.0, /* Z far */ 800.0);
	glMatrixMode(GL_MODELVIEW);
	gluLookAt(0.0, 0.0, 500.0,  /* eye is at (0,0,30) */
		0.0, 0.0, 0.0,      /* center is at (0,0,0) */
		0.0, 1.0, 0.0);      /* up is in postivie Y direction */

	glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);

	glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
	glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.001);
	glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.001);

	glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor1);
	glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.001);
	glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.001);

	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);

//	Modelling();
}
//---------------------------------------------------------------------------
bool __fastcall TThreeDImageViewerForm::SetupPixelFormat(HDC hdc)
{
	PIXELFORMATDESCRIPTOR pfd, *ppfd;
	int pixelformat;

	ppfd = &pfd;

	ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
	ppfd->nVersion = 1;
	ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
						PFD_DOUBLEBUFFER;
	ppfd->dwLayerMask = PFD_MAIN_PLANE;
//	ppfd->iPixelType = PFD_TYPE_COLORINDEX;
	ppfd->iPixelType = PFD_TYPE_RGBA;
	ppfd->cColorBits = 32;
	ppfd->cDepthBits = 16;

	ppfd->cAccumBits = 0;
	ppfd->cStencilBits = 0;

	if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 )
	{
		MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
		return FALSE;
	}

	if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
	{
		MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
		return FALSE;
	}

	return TRUE;
}
//---------------------------------------------------------------------------
void __fastcall TThreeDImageViewerForm::Set3DImage(Graphics::TBitmap *bitmap,
	unsigned char tabletColorB, unsigned char tabletColorG, unsigned char tabletColorR,
	int defectLeft, int defectTop, int defectRight, int defectBottom)
{
		int BitmapWidth = bitmap->Width;
		int BitmapHeight = bitmap->Height;
		int halfBitmapWidth = BitmapWidth / 2;
		int halfBitmapHeight = BitmapHeight / 2;
		byte *BitmapData = new byte[BitmapWidth * BitmapHeight];
		if (bitmap->PixelFormat == pf24bit)
		{
			for (int y = 0; y < BitmapHeight; y++)
			{
				byte *pBitmap = (byte *)bitmap->ScanLine[y];
				for (int x = 0; x < BitmapWidth; x++)
				{
					BitmapData[y * BitmapWidth + x] = pBitmap[3 * x];
				}
			}
		}
		else
		{
			for (int y = 0; y < BitmapHeight; y++)
			{
				byte *pBitmap = (byte *)bitmap->ScanLine[y];
				for (int x = 0; x < BitmapWidth; x++)
				{
					BitmapData[y * BitmapWidth + x] = pBitmap[x];
				}
			}
		}


		glNewList(TABLET, GL_COMPILE);
//		glShadeModel(GL_SMOOTH);
		glBegin(GL_TRIANGLES);

		int rangeLeft, rangeTop, rangeRight, rangeBottom;
		if (BitmapWidth <= 320)
		{
			rangeLeft = defectLeft / 2;
			rangeTop = defectTop;
			rangeRight = defectRight / 2;
			rangeBottom = defectBottom;
		}
		else
		{
			rangeLeft = defectLeft;
			rangeTop = defectTop;
			rangeRight = defectRight;
			rangeBottom = defectBottom;
		}

		
		if (rangeLeft < 0) rangeLeft = 0;
		if (rangeLeft >= BitmapWidth) rangeLeft = BitmapWidth;
		if (rangeRight < 0) rangeRight = 0;
		if (rangeRight >= BitmapWidth) rangeRight = BitmapWidth;
		if (rangeTop < 0) rangeTop = 0;
		if (rangeTop >= BitmapHeight) rangeTop = BitmapHeight;
		if (rangeBottom < 0) rangeBottom = 0;
		if (rangeBottom >= BitmapHeight) rangeBottom = BitmapHeight;

		const float cThreeDHeight = 0.3;
		if (BitmapWidth <= 320)
		{
			for (int y = 0; y < BitmapHeight - 1; y++)
			{
				for (int x = 0; x < BitmapWidth - 1; x++)
				{
					if (BitmapData[y * BitmapWidth + x] > 0)
					{
						if (y >= rangeTop && y < rangeBottom && x >= rangeLeft && x < rangeRight) continue;
						glVertex3f(x - halfBitmapWidth, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f(x + 1 - halfBitmapWidth, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x + 1] - 128) * cThreeDHeight);
						glVertex3f(x + 1 - halfBitmapWidth, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x + 1] - 128) * cThreeDHeight);

						glVertex3f(x - halfBitmapWidth, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f(x - halfBitmapWidth, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f(x + 1 - halfBitmapWidth, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x + 1] - 128) * cThreeDHeight);
					}
				}
			}
		}
		else
		{
			for (int y = 0; y < BitmapHeight - 1; y++)
			{
				for (int x = 0; x < BitmapWidth - 1; x++)
				{
					if (BitmapData[y * BitmapWidth + x] > 0)
					{
						if (y >= rangeTop && y < rangeBottom && x >= rangeLeft && x < rangeRight) continue;
						glVertex3f((x - halfBitmapWidth) * 0.5, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f((x + 1 - halfBitmapWidth) * 0.5, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x + 1] - 128) * cThreeDHeight);
						glVertex3f((x + 1 - halfBitmapWidth) * 0.5, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x + 1] - 128) * cThreeDHeight);

						glVertex3f((x - halfBitmapWidth) * 0.5, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f((x - halfBitmapWidth) * 0.5, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f((x + 1 - halfBitmapWidth) * 0.5, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x + 1] - 128) * cThreeDHeight);
					}
				}
			}
		}

		glEnd();
		glEndList();

		glNewList(DEFECT_AREA, GL_COMPILE);
		glBegin(GL_TRIANGLES);

		if (BitmapWidth <= 320)
		{
			for (int y = rangeTop; y < rangeBottom; y++)
			{
				for (int x = rangeLeft; x < rangeRight; x++)
				{
					if (BitmapData[y * BitmapWidth + x] > 0)
					{
						glVertex3f(x - halfBitmapWidth, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f(x + 1 - halfBitmapWidth, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x + 1] - 128) * cThreeDHeight);
						glVertex3f(x + 1 - halfBitmapWidth, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x + 1] - 128) * cThreeDHeight);

						glVertex3f(x - halfBitmapWidth, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f(x - halfBitmapWidth, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f(x + 1 - halfBitmapWidth, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x + 1] - 128) * cThreeDHeight);
					}
				}
			}
		}
		else
		{
			for (int y = rangeTop; y < rangeBottom; y++)
			{
				for (int x = rangeLeft; x < rangeRight; x++)
				{
					if (BitmapData[y * BitmapWidth + x] > 0)
					{
						glVertex3f((x - halfBitmapWidth) * 0.5, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f((x + 1 - halfBitmapWidth) * 0.5, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x + 1] - 128) * cThreeDHeight);
						glVertex3f((x + 1 - halfBitmapWidth) * 0.5, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x + 1] - 128) * cThreeDHeight);

						glVertex3f((x - halfBitmapWidth) * 0.5, (halfBitmapHeight - y) * 0.5, (BitmapData[y * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f((x - halfBitmapWidth) * 0.5, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x] - 128) * cThreeDHeight);
						glVertex3f((x + 1 - halfBitmapWidth) * 0.5, (halfBitmapHeight - y - 1) * 0.5, (BitmapData[(y + 1) * BitmapWidth + x + 1] - 128) * cThreeDHeight);
					}
				}
			}
		}

		glEnd();
		glEndList();

	colorB = tabletColorB;
	colorG = tabletColorG;
	colorR = tabletColorR;
	Angle = Angle2 = 0;

//	RedrawGL();
	Repaint();

	delete[] BitmapData;
}
//---------------------------------------------------------------------------
void __fastcall TThreeDImageViewerForm::FormActivate(TObject *Sender)
{
	wglMakeCurrent(GHDC, GLRC);
//	RedrawGL();
//	Repaint();
//	RedrawTimer->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TThreeDImageViewerForm::ImagePanelMouseDown(
      TObject *Sender, TMouseButton Button, TShiftState Shift, int X,
      int Y)
{
	if (Shift.Contains(ssLeft))
	{
		StartX = X;
		StartY = Y;
	}
}
//---------------------------------------------------------------------------

void __fastcall TThreeDImageViewerForm::ImagePanelMouseMove(
      TObject *Sender, TShiftState Shift, int X, int Y)
{
	if (Shift.Contains(ssLeft)) {
		Angle = Angle + (X - StartX) * 0.2;
		Angle2 = Angle2 + (Y - StartY);
		if (Angle2 < MIN_ROTATE_Y_ANGLE) Angle2 = MIN_ROTATE_Y_ANGLE;
		if (Angle2 > MAX_ROTATE_Y_ANGLE) Angle2 = MAX_ROTATE_Y_ANGLE;

		StartX = X;
		StartY = Y;
		Repaint();
	}	
}
//---------------------------------------------------------------------------

void __fastcall TThreeDImageViewerForm::FormPaint(TObject *Sender)
{
	RedrawGL();
}
//---------------------------------------------------------------------------
void __fastcall TThreeDImageViewerForm::RedrawGL(void)
{
//	GLfloat lightZeroPosition[] = {0.0, -120, 500.0, 100.0};
//	GLfloat lightZeroPosition[] = {0.0, -300, 3000.0, 20};
//	GLfloat lightZeroDirection[] = {0, 0.1, -1};
	GLfloat lightZeroPosition[] = {0.0, 3000, 300.0, 20};
	GLfloat lightZeroDirection[] = {0, -1, -0.1};
//	GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0};

	GLfloat lightOnePosition[] = {0.0, -3000, -300.0, 10};
	GLfloat lightOneDirection[] = {0, 1, 0.1};

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//	glDisable(GL_LIGHT0);
//	glEnable(GL_LIGHT0);


	glPushMatrix();
	glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightZeroDirection);

	glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
	glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, lightOneDirection);

//	glTranslatef(0, 50, 0);
	/* Perform scene rotations based on user mouse input. */
	glRotatef(Angle2, 1.0, 0.0, 0.0);
//	glRotatef(Angle, 0.0, 1.0, 0.0);
	glRotatef(Angle, 0.0, 0.0, 1.0);



//	glColor4f(0.7, 0.0, 0.0, 0.3);
	GLfloat skinColor[4];
	skinColor[0] = colorR / 255.0;
	skinColor[1] = colorG / 255.0;
	skinColor[2] = colorB / 255.0;
	skinColor[3] = 1.0;

	glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);

	glCallList(TABLET);

	GLfloat defectSkinColor[] = {1.0, 0.0, 0.0, 1.0};
	if (ShowDefectArea)
	{
		glMaterialfv(GL_FRONT, GL_DIFFUSE, defectSkinColor);
	}
	glCallList(DEFECT_AREA);

	glFrontFace(GL_CW);  /* Switch face orientation. */
	glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
	glCallList(TABLET);

	if (ShowDefectArea)
	{
		glMaterialfv(GL_FRONT, GL_DIFFUSE, defectSkinColor);
	}
	glCallList(DEFECT_AREA);	
	glFrontFace(GL_CCW);

	
	glPopMatrix();
	SwapBuffers(GHDC);
}
//---------------------------------------------------------------------------

void __fastcall TThreeDImageViewerForm::PositionResetButtonClick(
      TObject *Sender)
{
	Angle = Angle2 = 0;
	RedrawGL();
}
//---------------------------------------------------------------------------

void __fastcall TThreeDImageViewerForm::DefectAreaButtonClick(
      TObject *Sender)
{
	ShowDefectArea = !ShowDefectArea;
	RedrawGL();
}
//---------------------------------------------------------------------------

void __fastcall TThreeDImageViewerForm::FormShow(TObject *Sender)
{
//	Repaint();
//	RedrawGL();
	RedrawTimer->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TThreeDImageViewerForm::RedrawTimerTimer(TObject *Sender)
{
	RedrawGL();
}
//---------------------------------------------------------------------------

void __fastcall TThreeDImageViewerForm::FormHide(TObject *Sender)
{
	RedrawTimer->Enabled = false;	
}
//---------------------------------------------------------------------------

