void CScanFashionDlg::OnBnClickedButtonAreaUp()
{
	if ( ! UpdateData(TRUE) )
	{
		return;
	}
	if (m_area_updown==0)
	{
		return;
	}

	float tf = m_rightdown_position.y + m_area_updown*1000;   // um
    
	if ( (tf+m_area_vertical*1000) > m_mechanical_vertical )
	{
		AfxMessageBox(_T("扫描范围超出机械行程"));
		return;
	}
	
	m_rightdown_position.y = tf;

	control_change();

	UpdateData(FALSE);
}
void CScanFashionDlg::OnBnClickedButtonAreaRight()
{
	if ( ! UpdateData(TRUE) )
	{
		return;
	}
	if (m_area_leftright==0)
	{
		return;
	}

	float tf = m_rightdown_position.x - m_area_leftright*1000;   // um
    
	if ( tf < 0 )
	{
		AfxMessageBox(_T("扫描范围超出机械行程"));
		return;
	}
	
	m_rightdown_position.x = tf;

	control_change();

	UpdateData(FALSE);
}
void CScanFashionDlg::OnBnClickedRadioLefttop()
{
	if ( ! UpdateData(TRUE) )
	{
		return;
	}
	
	control_change();

	UpdateData(FALSE);
}
void CScanFashionDlg::OnBnClickedRadioContinue()
{
	if ( ! UpdateData(TRUE) )
	{
		return;
	}
	m_ctl_BestScanRoute.EnableWindow(FALSE);
	EnableScanSet(TRUE);	
	control_change();
	UpdateData(FALSE);
}
void CScanFashionDlg::OnBnClickedRadioNinepoint()
{
	if ( ! UpdateData(TRUE) )
	{
		return;
	}
	m_ctl_BestScanRoute.EnableWindow(FALSE);
	EnableScanSet(FALSE);
	m_scan_origin = SCAN_ORIGIN_RIGHT_DOWN;
	control_change();
	UpdateData(FALSE);
}
// 向View视图发送消息,通知其更新扫描路径
void CScanFashionDlg::OnBnClickedApply()
{
	UpdateData(TRUE);
	control_change();

	SCANROUTE		scanroute; 
	getScanRoute(scanroute);
	g_Mechanism.SetScanRoute(&scanroute);

	if ( ! ( GetParentFrame()->GetActiveView()->PostMessageW(MSG_SCANROUTE_NOTIFY, 0L, 0L) ) )
	{
		AfxMessageBox(_T("不能将扫描方式设置对话框的消息发送出去"));
	}
}
void CScanFashionDlg::OnBnClickedCheckBestscanroute()
{
	if ( m_bBestScanRoute )
	{
		m_bBestScanRoute = FALSE;
		m_ctl_BestScanRoute.SetCheck(BST_UNCHECKED);
		EnableScanSet(TRUE);		
	}
	else
	{
		m_bBestScanRoute = TRUE;
		m_ctl_BestScanRoute.SetCheck(BST_CHECKED);
		EnableScanSet(FALSE);
	}

	control_change();
	UpdateData(FALSE);
}
void CScanFashionDlg::OnEnChangeEditVerticalNum()
{
	UINT last_view_row_num;
	last_view_row_num = m_view_row_num;

	if ( ! UpdateData(TRUE) )
	{
		return;
	}
	m_view_total_num = m_view_row_num * m_view_column_num;

	if ( !control_change() )
	{
	    m_view_row_num = last_view_row_num;
	}
	m_view_total_num = m_view_row_num * m_view_column_num;

	UpdateData(FALSE);
}
CScanFashionDlg::CScanFashionDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CScanFashionDlg::IDD, pParent)
	, m_hSlidBitmap(NULL)
	, m_slidebmp_width(380)
	, m_slidebmp_height(552)
	, m_slidebmp_byteCount(m_slidebmp_width*m_slidebmp_height*4)
	, m_scan_fashion_display_ratio(25000.0/285)
	, m_slidebmp_origin(332,454)
	, m_ninepoint_horizon_distance(6)   // mm
	, m_ninepoint_vertical_distance(6)  // mm
	, m_continue_horizon_overlap(0)
	, m_continue_vertical_overlap(0)
	, m_area_updown(0)
	, m_area_leftright(0)
	, m_mechanical_horizon(25000)
	, m_mechanical_vertical(26000)
	, m_view_width(87.72)     // um
	, m_view_height(66.048)   // um
{
	// default position of the first view
	m_rightdown_position.x = 6500;  // um
	m_rightdown_position.y = 6000;  // um

	// default distributed fashion: average
	m_view_distribute = VIEW_DISTRIBUTE_AVERAGE;
	m_view_column_num = 20;
	m_view_row_num = 15;
	m_average_horizon_distance = 631.579;      // um
	m_average_vertical_distance = 857.143;     // um

	// default scan sequence
	m_bBestScanRoute = TRUE;
	m_scan_origin = SCAN_ORIGIN_RIGHT_DOWN;   // start view: rightdown
	m_scan_fashion = SCAN_FASHION_HORIZON;   // vertical

	control_change();

	g_Mechanism.SetScanRoute(m_view_row_num, m_view_column_num, m_area_topology, m_area_scan_sequence);
}
int main(int argc, char ** argv)
{
  static msg_block_t msg;
  memset((void *)&msg, 0, sizeof(msg));
  struct timespec time;
  double time0, time1;
  uint32_t notes[SCALE_PATTERN][NOTES_SIZE];
  uint32_t scales[SCALE_PATTERN][SCALE_SIZE] = {
    {0,4,7,9,},
    {0,5,7,9,},
    {2,4,7,11,},
    {2,5,7,9,},
    {2,5,7,11,},
    {0,2,4,7,},
    {0,2,5,7,},
    {0,2,5,9,},
  };
  uint32_t instruments[] = {
    0, 4, 5, 6, 8, 9, 11, 14, 15, 16, 17, 19, 24,
    25, 26, 30, 40, 42, 46, 48, 51, 52, 56, 57, 60,
    61, 63, 64, 65, 68, 69, 70, 73, 88, 89, 91, 93,
    94, 95, 98, 99, 103, 104, 110, 
  };
  uint32_t insts = sizeof(instruments) / sizeof(uint32_t);

  int fb = open(FBDEV, O_RDWR);
  if (fb > 0)
  {
    struct fb_fix_screeninfo fbfsi;
    struct fb_var_screeninfo fbvsi;
    if (ioctl(fb, FBIOGET_FSCREENINFO, &fbfsi) == 0)
    {
      msg.fbinfo.smem_start = fbfsi.smem_start;
      msg.fbinfo.smem_len = fbfsi.smem_len;
      msg.fbinfo.line_length = fbfsi.line_length;
    }
    if (ioctl(fb, FBIOGET_VSCREENINFO, &fbvsi) == 0)
    {
      msg.fbinfo.xres = fbvsi.xres;
      msg.fbinfo.yres = fbvsi.yres;
      msg.fbinfo.xres_virtual = fbvsi.xres_virtual;
      msg.fbinfo.yres_virtual = fbvsi.yres_virtual;
      msg.fbinfo.xoffset = fbvsi.xoffset;
      msg.fbinfo.yoffset = fbvsi.yoffset;
      msg.fbinfo.bits_per_pixel = fbvsi.bits_per_pixel;
    }
    close(fb);
  }

  long pagesize = (sysconf(_SC_PAGESIZE));
  int fdmem = open(MEMDEV, O_RDWR | O_SYNC);
  uint32_t *frame_buffer = NULL;
  size_t mapsize = 0;
  if ((fdmem > 0) && (msg.fbinfo.smem_start != 0))
  {
    off_t physical_page = msg.fbinfo.smem_start & (~(pagesize - 1));
    unsigned long offset = msg.fbinfo.smem_start - (unsigned long)physical_page;
    mapsize = msg.fbinfo.smem_len + offset;
    frame_buffer = mmap(NULL, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fdmem, physical_page);
    if (frame_buffer == MAP_FAILED)
    {
      perror("Framebuffer Map Failed");
    }
  }

  struct timespec time_start;
  clock_gettime(CLOCK_MONOTONIC_RAW, &time_start);
  srand((uint32_t)time_start.tv_nsec);

  seq_context_t seq;

  if (open_sequencer(&seq) == FALSE)
  {
    exit(EXIT_FAILURE);
  }
  program_change(&seq, 0, 48);
  control_change(&seq, 0, 91, 127);

  static rt_context_t rtx;
  memset((void *)&rtx, 0, sizeof(rtx));

  int width = msg.fbinfo.xres_virtual;
  int height = msg.fbinfo.yres_virtual;
  rtx.objnum = OBJNUM;
  rtx.light.pos = vec3_set(-4.0f, 8.0f, 2.0f);
  rtx.light.col = vec3_set(1.0f, 1.0f, 1.0f);
  rtx.eye = vec3_set(0.0f, 0.0f, -7.0f);
  rtx.swidth = 10.0f * (float)width / (float)height;
  rtx.sheight = 10.0f;
  rtx.width = width / SCALE;
  rtx.height = height / SCALE;
  rtx.xoff = 0;
  rtx.yoff = 0;
  rtx.ax = rtx.swidth / (float)rtx.width;
  rtx.ayc = rtx.sheight / (float)rtx.height;
  rtx.ay = rtx.sheight / (float)rtx.height;

  uint32_t i, j;
  for (i = 0; i < SCALE_PATTERN; i++)
  {
    for (j = 0; j < NOTES_SIZE; j++)
    {
      notes[i][j] = scales[i][j % SCALE_SIZE] + (j / SCALE_SIZE) * 12;
    }
  }

  for (i = 0; i < rtx.objnum; i++)
  {
    rtx.obj[i].type = SPHERE;
    rtx.obj[i].pos = vec3_set(0.0f, -100.0f, 0.0f);
    rtx.obj[i].rad = 1.0f;
    rtx.obj[i].col = vec3_set(randf(), randf(), randf());
    rtx.obj[i].flag_shadow = TRUE;
    rtx.obj[i].flag_refrect = TRUE;
    rtx.obj[i].spd = vec3_set(0.0f, 0.0f, 0.0f);
    rtx.obj[i].note = 0;
  }

  rtx.obj[0].type = PLANE;
  rtx.obj[0].norm = normalize(vec3_set(0.0f, 1.0f, 0.0f));
  rtx.obj[0].dist = 2.0f;
  rtx.obj[0].col = vec3_set(0.1f, 0.3f, 0.6f);
  rtx.obj[0].flag_shadow = TRUE;
  rtx.obj[0].flag_refrect = TRUE;
  rtx.obj[0].spd = vec3_set(0.0f, 0.0f, 0.0f);

  uint32_t scale = 0;
  uint32_t curobj = 0;
  float next_note_time = get_elapsed(time_start) + 3.0f;
  float next_scale_time = get_elapsed(time_start) + 15.0f + randf() * 15.0f;
  float time_now = get_elapsed(time_start);
  float time_quit = time_now + 3600.0f;
  uint32_t retry_count = 0;
  uint32_t counter = 0;
  float time_prev = 0.0f;
  while(time_now < time_quit)
  {
    uint32_t e;
    for (e = 1; e < rtx.objnum; e++)
    {
      rtx.obj[e].pos = vec3_add(rtx.obj[e].pos, rtx.obj[e].spd);
    }
    time_now = get_elapsed(time_start);
    if (time_now > next_note_time)
    {
      e = (curobj % (rtx.objnum - 1)) + 1;
      rtx.obj[e].pos = vec3_set(randf()*8.0f-4.0f, randf()*6.0f-1.0f, randf()*8.0+0.0f);
      rtx.obj[e].col = vec3_set(randf(), randf(), randf());
      rtx.obj[e].spd = vec3_set(randf()*0.1f-0.05f,randf()*0.1f-0.05f,randf()*0.1f-0.05f);
      note_off(&seq, 0, rtx.obj[e].note);
      rtx.obj[e].note = notes[scale][(uint32_t)(randf() * 17.0f) + 12];
      note_on(&seq, 0, rtx.obj[e].note, 127 - rtx.obj[e].note);
      curobj++;
      float len = (randf() + 0.5f);
      next_note_time = time_now + len * len * len;
    }
    if (time_now > next_scale_time)
    {
      scale = (uint32_t)(randf() * (float)SCALE_PATTERN);
      program_change(&seq, 0, instruments[(uint32_t)(randf() * ((float)insts + 0.99f))]);
      rtx.obj[0].col = vec3_set(randf(), randf(), randf());
      rtx.light.pos = vec3_set(randf() * 8.0f - 4.0f, 8.0f, randf() * 4.0f);
      next_scale_time = time_now + (randf() + 0.1f) * 40.0f;
    }

    render(&msg, &rtx, frame_buffer);

    counter++;
    if (counter > 100)
    {
      //printf("FPS: %.2f\n", 100.0f / (time_now - time_prev));
      time_prev = time_now;
      counter = 0;
    }
  }

  close_sequencer(&seq);
  munmap(frame_buffer, mapsize);
  close(fdmem);
  return 0;
}