// 2DBathyDisplay.cpp: implementation of the C2DBathyDisplay class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "2DBathyDisplay.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

C2DBathyDisplay::C2DBathyDisplay()
{
  
  m_dMinDistance   = 0.0;
  m_dMaxDistance   = 0.0;//150.0;
  m_dMinDepth      = 0.0;//13.0;
  m_dMaxDepth      = 0.0;//45.0;
  m_dRealMaxDepth  = 0;//21;
  m_dRealMinDepth  = 0;//20;
  m_fMouseCoordX   = -0.1f;
  m_fMouseCoordY   = -0.1f;
  m_dwValues       = 0;
  m_bLeftDown      = FALSE;
  m_bFlip		   = FALSE;
  m_dwPointsColor  = GLBLUE;
  m_fPointSize	   = 1.7f;
  m_fPointSpacing  = .03f;

  m_pBathyHistory = new BATHY_POINTS[MAX_HIST_POINTS];
  m_pBathyHistory[0].numPoints = -1;

}

C2DBathyDisplay::~C2DBathyDisplay()
{
  delete [] m_pBathyHistory;
  m_pBathyHistory = NULL;
}


BEGIN_MESSAGE_MAP(C2DBathyDisplay, CWnd)
	//{{AFX_MSG_MAP(COpenGLBase)
  ON_WM_PAINT()
  ON_WM_ERASEBKGND()
  ON_WM_SIZE()
  ON_WM_MOUSEMOVE()
  ON_WM_LBUTTONDOWN()
  ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

DWORD C2DBathyDisplay::Render(BOOL flag)
{
  if(!m_bInit)
    return 1;

  wglMakeCurrent(m_hDC, m_hRC);

  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glLoadIdentity();			

  glTranslatef(-0.5f,-0.5f, -1.2f);
   
  glEnable(GL_LINE_SMOOTH);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glPointSize(m_fPointSize);
  //glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
 
  //glRotatef(m_dXAngle, 0.0, 0.0, 1.0);
  //glRotatef(-5.0, 0.0, 1.0, 0.0);
  //glRotatef(-35.0f, 0,1,0);
  //glRotatef(10.0f, 1,0,0);

  DraxAxis();
  glBegin(GL_LINES);
  glVertex3f(0.0f,0.0f,0.0f);
  glVertex3f(0.0f,0.0f,-2.0);
  glEnd();
  //DrawCurrentDepth();
  DrawCurve(flag);
  DrawMouseCoord();
  DrawMeasureLine();
 
  gl_setcolor(GLWHITE);

  glDisable(GL_LINE_SMOOTH);
  glDisable(GL_BLEND);

  glFlush();

  return 1;
}



DWORD C2DBathyDisplay::DraxAxis()
{
  char label[128];
  float offset, text_width, text_height, distance_steps, depth_steps, swath_half;
  int i;

  gl_setcolor(GLWHITE);

  sprintf(label, "Depth [m]");
  text_width = glGetTextWidth(label);
  glRasterPos2f(-text_width - 0.01f, 0.999f);
  glPrint(label);
  
  sprintf(label, "Swath [m]");
  glRasterPos2f(1.0f, -0.02f);
  glPrint(label);
  
  // Axis
  gl_line(0.0f, 0.0f, 0.0f, 1.0f);
  gl_line(0.0f, 0.0f, 1.0f, 0.0f);

  gl_line(0.0f, 1.0f, 0.01f, 0.99f);
  gl_line(0.0f, 1.0f, -0.01f, 0.99f);
  gl_line(1.0f, 0.0f, 0.99f, 0.01f);
  gl_line(1.0f, 0.0f, 0.99f, -0.01f);

  depth_steps = (float)((m_dMaxDepth - m_dMinDepth) / 8.0);
  // Y
  for(i=0;i<9;i++)
  {
    sprintf(label, "-%.0lf", (double)m_dMaxDepth - i*depth_steps);
    text_width = glGetTextWidth(label);
    text_height = glGetTextHeight();
    
    offset = (float)(i * 0.1 + 0.1);
    gl_line(-0.02f, offset, 0.02f, offset);

    glRasterPos3f(-text_width - 0.01f, offset - text_height/2.0f, .06f);
    glPrint(label);
  }

  distance_steps = (float)((m_dMaxDistance - m_dMinDistance) / 8.0);
  swath_half = (float)((m_dMaxDistance - m_dMinDistance) * 0.5);
  // X
  for(i=0;i<9;i++)
  {
    sprintf(label, "%.0lf", (double)-swath_half + i*distance_steps);
    text_width = glGetTextWidth(label);

    offset = (float)(i * 0.1 + 0.1);
    gl_line(offset, -0.02f, offset, 0.02f);

    glRasterPos3f(offset - text_width/(float)2.0, -0.01f - text_height, .06f);
    glPrint(label);
  
  }

  return 1;
}

DWORD C2DBathyDisplay::DrawMouseCoord()
{
  float text_width, text_height;
  double sv, depth, swath_half;

  if(m_fMouseCoordX < 0.1 || m_fMouseCoordY < 0.0 || m_fMouseCoordX > 0.9 || m_fMouseCoordY > 0.9)
    return 0;

  gl_setcolor(GLBLACK);
  
  swath_half = (float)((m_dMaxDistance - m_dMinDistance) * 0.5);

  sv = -swath_half + ((m_fMouseCoordX-0.1f) / 0.8f) * (m_dMaxDistance - m_dMinDistance);
  depth = m_dMinDepth + ((0.9f - m_fMouseCoordY) / 0.8f) * (m_dMaxDepth - m_dMinDepth);

  sprintf(m_labels, "DEPTH:");
  text_width = glGetTextWidth(m_labels);
  
  sprintf(m_labels, "DEPTH: %.1lf m", depth);
  text_height = glGetTextHeight();
  glRasterPos2f(1.0f - text_width, 1.0f - text_height);
  glPrint(m_labels);

  sprintf(m_labels, "SWATH:", sv);
  text_width = glGetTextWidth(m_labels);
  
  sprintf(m_labels, "SWATH: %.1lf m", sv);
  text_height = glGetTextHeight();
  glRasterPos2f(1.0f - text_width, 1.0f - 2.5f*text_height);
  glPrint(m_labels);


  return 1;
}

DWORD C2DBathyDisplay::DrawCurve(BOOL skipMemMove)
{
  DWORD i;
  double div_depth, div_dist, depth1, dist1;
  double paletteDiv;

  if(m_dwValues < 2)
    return 0;

  //gl_setcolor(m_dwPointsColor);

  if(m_dMaxDepth == m_dMinDepth)
		m_dMaxDepth += .1; //this is lame!

  if(m_dMaxDistance == m_dMinDistance)
		m_dMaxDistance += .1; //this is lame!


  div_depth		= 1.0 / (m_dMaxDepth - m_dMinDepth);
  div_dist		= 1.0 / (m_dMaxDistance - m_dMinDistance);
  paletteDiv	= abs((int)(256.0/(m_dRealMaxDepth - m_dRealMinDepth)));

  TRACE("Real Min = %.2f    Real Max = %.2f \r\n",m_dRealMinDepth,m_dRealMaxDepth);

  glPointSize(1.2);

  if(m_pBathyHistory[0].numPoints != -1)
  {
	glBegin(GL_POINTS);

	for(int x = 0; x<MAX_HIST_POINTS; x++)
	{
		if(m_pBathyHistory[x].numPoints <= 0)
		{

			TRACE("NO POINTS CONTINUE ON %d\r\n", x);
			continue;
		
		}
		
		//div_depth = 1.0 / (m_pBathyHistory[x].maxDepth - m_pBathyHistory[x].minDepth);
		//div_dist  = 1.0 / (m_pBathyHistory[x].maxDist - m_pBathyHistory[x].minDist);
		int numPoints = m_pBathyHistory[x].numPoints;

		if(m_bFlip)
		{
			
			for(int xx = 0; xx < numPoints; xx++)
			{
			
				depth1   = (m_pBathyHistory[x].Depths[xx]      - m_dMinDepth) * div_depth;			
				
				//this is a BAD way, but I kept it here for reference
				//dist1    = (m_pBathyHistory[x].Distances[numPoints -xx - 1]   - m_dMinDistance - m_dDistanceOffset) * div_dist;
				dist1    = 1 - (m_pBathyHistory[x].Distances[xx]   - m_dMinDistance - m_dDistanceOffset) * div_dist;

				int index = (int)floor( (m_pBathyHistory[x].Depths[xx]-m_pBathyHistory[x].minDepth)*paletteDiv +.5);
		
				if(index > 255)
					index = 255;
				else if(index<0)
					index = 0;

				int color = (DWORD)m_rgbPalette[ 255 - index ].colorValue;
		
				gl_setcolor(color);
				//gl_setcolor(GLWHITE);
				glVertex3d((0.8f * dist1 + 0.1f)+x*.01, (0.9f - 0.8f * (float)depth1)+x*.012+.012,-m_fPointSpacing - x*m_fPointSpacing);
			}
		}
		else
		{
			for(int xx = 0; xx < numPoints; xx++)
			{
			
				depth1   = (m_pBathyHistory[x].Depths[xx]      - m_dMinDepth) * div_depth;			
				dist1    = (m_pBathyHistory[x].Distances[xx]   - m_dMinDistance - m_dDistanceOffset) * div_dist;
			
				int index = (int)floor( (m_pBathyHistory[x].Depths[xx]-m_pBathyHistory[x].minDepth)*paletteDiv +.5);
		
				if(index > 255)
					index = 255;
				else if(index<0)
					index = 0;

				int color = (DWORD)m_rgbPalette[ 255 - index ].colorValue;
		
				gl_setcolor(color);
				//gl_setcolor(GLWHITE);
				glVertex3d((0.8f * dist1 + 0.1f)+x*.01, (0.9f - 0.8f * (float)depth1)+x*.01+.012,-m_fPointSpacing - x*m_fPointSpacing);
			}
		}
//
//		TRACE("DREW DEPTH LINE %d\r\n", xx);
	}
	glEnd();
  }

  //gl_setcolor(RED);
  glPointSize(3);
  glBegin(GL_POINTS);

  //maybe this should be moved to the top, and all the history points should 
  //be drawn based on the CURRENT MIN/MAX depth instead of the history value
  div_depth = 1.0 / (m_dMaxDepth - m_dMinDepth);
  div_dist  = 1.0 / (m_dMaxDistance - m_dMinDistance);

  if(m_bFlip)
  {
	for(i=0;i<m_dwValues;i++)
	{
	
		depth1	 = (m_pDepths[i]	 - m_dMinDepth) * div_depth;
		//this is a BAD way, but I kept it here for reference
		//dist1    = (m_pDistances[m_dwValues - i -1]  - m_dMinDistance - m_dDistanceOffset) * div_dist;
		dist1    = 1 - (m_pDistances[i]  - m_dMinDistance - m_dDistanceOffset) * div_dist;

		int index = (int)floor( (m_pDepths[i]-m_dRealMinDepth)*paletteDiv +.5);
		
		if(index > 255)
			index = 255;
		else if(index<0)
			index = 0;

		TRACE("Index = %d\r\n", index);
		int color = (DWORD)m_rgbPalette[ 255 - index ].colorValue;
		
		gl_setcolor(color);
		//gl_setcolor(BLUE);
		glVertex3d(0.8f * dist1 + 0.1f, 0.9f - 0.8f * (float)depth1,0);
	}
  }
  else
  {
	for(i=0;i<m_dwValues;i++)
	{
	
		depth1	 = (m_pDepths[i]	 - m_dMinDepth) * div_depth;
		dist1    = (m_pDistances[i]  - m_dMinDistance - m_dDistanceOffset) * div_dist;

		int index = (int)floor( (m_pDepths[i]-m_dRealMinDepth)*paletteDiv +.5 );
		if(index > 255)
			index = 255;
		else if(index<0)
			index = 0;
		TRACE("Index = %d\r\n", index);
		int color = (DWORD)m_rgbPalette[ 255 - index ].colorValue;
		
		gl_setcolor(color);
		//gl_setcolor(BLUE);
		glVertex3d(0.8f * dist1 + 0.1f, 0.9f - 0.8f * (float)depth1,0);
	}
	
  }
  
  glEnd();
  glPointSize(m_fPointSize);

  
  //Draw the min max markers on the Y axis	
  gl_setcolor(GLRED);
  double line_width;
  glGetDoublev(GL_LINE_WIDTH, &line_width);
  glLineWidth((float)(line_width*2.0));
  
  //output the lines
  gl_line(-0.02f, 0.9f - 0.8f * (float)(m_dRealMinDepth-m_dMinDepth)* div_depth, 0.02f, 0.9f - 0.8f * (float)(m_dRealMinDepth-m_dMinDepth)* div_depth);	
  gl_line(-0.02f, 0.9f - 0.8f * (float)(m_dRealMaxDepth-m_dMinDepth)* div_depth, 0.02f, 0.9f - 0.8f * (float)(m_dRealMaxDepth-m_dMinDepth)* div_depth);	
  
  //output the text label next to the line
  glRasterPos2f(0.02f, 0.9f - 0.8f * (float)(m_dRealMinDepth-m_dMinDepth)* div_depth);
  sprintf(m_labels,"%.1f", m_dRealMinDepth);
  glPrint(m_labels);
  glRasterPos2f(0.02f, 0.9f - 0.8f * (float)(m_dRealMaxDepth-m_dMinDepth)* div_depth);
  sprintf(m_labels,"%.1f", m_dRealMaxDepth);
  glPrint(m_labels);


  glLineWidth(line_width);
  
  
  if(skipMemMove == FALSE)
  {
		memmove(&m_pBathyHistory[1],&m_pBathyHistory[0], sizeof(BATHY_POINTS)*(MAX_HIST_POINTS-1));
  
		m_pBathyHistory[0].numPoints = m_dwValues;
		m_pBathyHistory[0].minDepth  = m_dRealMinDepth;//m_dMinDepth;//
		m_pBathyHistory[0].maxDepth  = m_dRealMaxDepth;//m_dMaxDepth;//
		m_pBathyHistory[0].minDist   = m_dMinDistance;
		m_pBathyHistory[0].maxDist   = m_dMaxDistance;
		m_pBathyHistory[0].distOff   = m_dDistanceOffset;
  
		memcpy(&m_pBathyHistory[0].Depths,    m_pDepths,    sizeof(double)*1024);
		memcpy(&m_pBathyHistory[0].Distances, m_pDistances, sizeof(double)*1024);
  }

  return 1;
}


void C2DBathyDisplay::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
	
	ResizeGL(cx, cy);

}

BOOL C2DBathyDisplay::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	
  Render(TRUE);	        			// Draw The Scene
  SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)

  return TRUE;
	//return CWnd::OnEraseBkgnd(pDC);
}

void C2DBathyDisplay::OnMouseMove(UINT nFlags, CPoint point) 
{
  // TODO: Add your message handler code here and/or call default
  /*
  GLint viewport[4];
  GLdouble mvmatrix[16], projmatrix[16];
  GLdouble wx, wy, wz;

  glGetIntegerv(GL_VIEWPORT, viewport);
  glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
  glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
  
  gluUnProject(point.x, viewport[3] - point.y, 0.0f, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
  m_fMouseCoordX = (float)wx;
  m_fMouseCoordY = (float)wy;

  Render(TRUE);	        			// Draw The Scene
  SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)
  */
  CWnd::OnMouseMove(nFlags, point);
}


void C2DBathyDisplay::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
  /*
  m_bLeftDown = TRUE;

  GLint viewport[4];
  GLdouble mvmatrix[16], projmatrix[16];
  GLdouble wx, wy, wz;

  glGetIntegerv(GL_VIEWPORT, viewport);
  glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
  glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
  
  gluUnProject(point.x, viewport[3] - point.y, 0.0f, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);

  m_fMouseCoordBDX = (float)wx;
  m_fMouseCoordBDY = (float)wy;

  Render(TRUE);	        			// Draw The Scene
  SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)

  CWnd::OnLButtonDown(nFlags, point);
*/
}

void C2DBathyDisplay::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	/*m_bLeftDown = FALSE;

  Render(TRUE);	        			// Draw The Scene
  SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)
	CWnd::OnLButtonUp(nFlags, point);

  */
}


DWORD C2DBathyDisplay::DrawMeasureLine()
{
  float text_width, text_height;
  char label[128];
  double x, y;//, z;

  if(m_bLeftDown == FALSE)
    return 0;

  gl_setcolor(GLRED);

  gl_dotted_line(m_fMouseCoordBDX, m_fMouseCoordBDY, m_fMouseCoordX, m_fMouseCoordY);

  x = (m_dMaxDistance - m_dMinDistance) * 1.25 * fabs(m_fMouseCoordBDX - m_fMouseCoordX);
  y = (m_dMaxDepth - m_dMinDepth) * 1.25 * fabs(m_fMouseCoordBDY - m_fMouseCoordY);
  //z = sqrt(x*x + y*y);
  
  sprintf(label, "X: %.1lfm Z: %.1lfm", x, y);
  text_width = glGetTextWidth(label);
  text_height = glGetTextHeight();
  glRasterPos2f(m_fMouseCoordX, m_fMouseCoordY + text_height);
  glPrint(label);

  return 1;
}

void C2DBathyDisplay::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here
	Render(TRUE);	        	// Draw The Scene
	SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)

	// Do not call CWnd::OnPaint() for painting messages
}

DWORD C2DBathyDisplay::ForceRender()
{
	Render(TRUE);	        	// Draw The Scene, no history increment
	SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)

	return 1;
}

DWORD C2DBathyDisplay::ForceFullRender()
{
	Render(FALSE);	        	// Draw The Scene with history increment
	SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)

	return 1;
}

void C2DBathyDisplay::SetPointColor( DWORD rgb)
{
	m_dwPointsColor = rgb;
	Render(TRUE);	        	// Draw The Scene
	SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)
}

void C2DBathyDisplay::SetPointSpace( float spacing)
{
	m_fPointSpacing = spacing;
	Render(TRUE);	        	// Draw The Scene
	SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)

}

void C2DBathyDisplay::SetPointSize( float size)
{
	m_fPointSize = size;
	Render(TRUE);	        	// Draw The Scene
	SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)
}

/* Make a linear gradient in the color array between two palette entries. */
void C2DBathyDisplay::RampColor(int first, int last, int r1, int g1, int b1, int r2, int g2, int b2)
{
  double r=r1+0.5, g=g1+0.5, b=b1+0.5, dr, dg, db;
  int i;

  if (first > last  ||  (unsigned)first > 255  ||  (unsigned)last > 255)
    return;             /* bad parameters */
  if (first == last)
    dr = dg = db = 0;
  else
  {
    dr = (double)(r2-r1) / (double)(last-first);
    dg = (double)(g2-g1) / (double)(last-first);
    db = (double)(b2-b1) / (double)(last-first);
  }
  for (i=first; i<=last; r+=dr,g+=dg,b+=db,i++)
  	m_rgbPalette[i].colorValue = RGB(r,g,b);
 
}

void C2DBathyDisplay::SetPalette( PALETTE_STYLE	pal )
{
	switch(pal)
	{

	case JET:		{
					  //RampColor(   0,  0,   0,  0,  0,    0,  0,  0);
					  RampColor(   0,  63,   0,  0,  64,    0,  0,255);
					  RampColor(  64, 127,   0,  0,255,    0,255,255);
					  RampColor( 128, 191,   0,255,255,  255,255,  0);
					  RampColor( 192, 255, 255,255,  0,  255,  0,  0);
					  break;
					}
	case SEABAT:	{
					  RampColor(   0,  0,   0,  0,  0,    0,  0,  0);
					  RampColor(   1, 16,   0,  0, 32,    0, 16, 48);
					  RampColor(  16, 32,   0, 16, 48,    0, 32, 64);
					  RampColor(  32, 48,   0, 32, 64,   16, 48, 80);
					  RampColor(  48, 64,  16, 48, 80,   32, 64, 80);
					  RampColor(  64, 80,  32, 64, 80,   48, 80, 80);
					  RampColor(  80, 96,  48, 80, 80,   64, 96, 80);
					  RampColor(  96,112,  64, 96, 80,   80,112, 80);
					  RampColor( 112,128,  80,112, 80,   96,128, 80);
					  RampColor( 128,144,  96,128, 80,  112,144, 80);
					  RampColor( 144,160, 112,144, 80,  128,160, 80);
					  RampColor( 160,176, 128,160, 80,  144,176, 80);
					  RampColor( 176,192, 144,176, 80,  160,192, 80);
					  RampColor( 192,208, 160,192, 80,  176,208, 80);
					  RampColor( 208,224, 176,208, 80,  208,224, 64);
					  RampColor( 224,240, 208,224, 64,  240,240, 48);
					  RampColor( 240,255, 240,240, 48,  255,255, 48);
					  break;
					}
	
	case DEFAULT:
	default:		{	
						RampColor(   0,  255,   255,  85,  45,    0,  220,  255);
						break;
					}




	}

	Render(FALSE);	        	// Draw The Scene
	SwapBuffers(m_hDC);			// Swap Buffers (Double Buffering)
}

void C2DBathyDisplay::SetFlip( BOOL bFlip )
{
	m_bFlip = bFlip;
}

void C2DBathyDisplay::ClearAll(	void )
{
	if(m_pBathyHistory)
		ZeroMemory(m_pBathyHistory, sizeof(BATHY_POINTS) * MAX_HIST_POINTS);

	//reinit some values
	m_dMinDistance   = 0.0;
	m_dMaxDistance   = 150.0;
	m_dMinDepth      = 13.0;
	m_dMaxDepth      = 45.0;
	m_dRealMaxDepth  = 21;
	m_dRealMinDepth  = 20;
}