void CAtmoGradients::SetActiveZone(int zone)
{
	if(!m_ZoneRadios || (zone<0)) return;


	CAtmoZoneDefinition *azone = m_pConfig->getZoneDefinition( zone );
	if(!azone) return;

	m_active_zone = zone;

	int *destWeight = new int[CAP_WIDTH * CAP_HEIGHT];

	azone->UpdateWeighting(destWeight, m_pConfig->getLiveView_WidescreenMode(), m_edge_weight);

	BITMAP bmp;
	int byte = (CAP_WIDTH * 4);
	if(byte & 1) 
		byte++;

	unsigned char *pixel_buffer = new unsigned char[byte * CAP_HEIGHT];
	unsigned char *tmp = pixel_buffer;
	for(int y = 0; y < CAP_HEIGHT; y++) 
	{
		tmp = pixel_buffer + y * byte;
		for(int x = 0; x < CAP_WIDTH; x++) 
		{
			*tmp = 0; tmp++; // R
			*tmp = (unsigned char)destWeight[y * CAP_WIDTH + x]; tmp++; // G
			*tmp = 0; tmp++; // B
			*tmp = 0; tmp++; // A
		}
	}

	bmp.bmType = 0;
	bmp.bmBitsPixel = 32;
	bmp.bmHeight = CAP_HEIGHT;
	bmp.bmWidth  = CAP_WIDTH;
	bmp.bmWidthBytes = byte;
	bmp.bmPlanes = 1;
	bmp.bmBits   = pixel_buffer;

	if(m_current_gradient)
	{
		DeleteObject( m_current_gradient );
		m_current_gradient = 0;
	}
	m_current_gradient = CreateBitmapIndirect(&bmp);
	DWORD error = GetLastError();

	delete []destWeight;
	delete []pixel_buffer;
}
ATMO_BOOL CAtmoGradients::HandleMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ 
	ATMO_BOOL r = CBasicDialog::HandleMessage(hwnd, uMsg, wParam, lParam);
	HWND groupBox = getDlgItem( IDC_ZONE_GROUP );
	CLanguage *Lng = new CLanguage;

	if((hwnd == groupBox) && (uMsg == WM_PAINT)) 
	{
		HDC hdc = GetDC(hwnd);
		HDC memDC = CreateCompatibleDC(hdc);
		RECT r;
		GetClientRect( groupBox, &r );
		int cx = (r.right - r.left) / 2;
		int cy = (r.bottom - r.top) / 2;

		HGDIOBJ oldObject = SelectObject( memDC, m_current_gradient );
		DWORD error = GetLastError();

		cx = cx - (CAP_WIDTH * 3) / 2;
		cy = cy - (CAP_HEIGHT * 3) / 2;

		StretchBlt( hdc, cx, cy, CAP_WIDTH*3, CAP_HEIGHT*3, memDC, 0, 0, CAP_WIDTH, CAP_HEIGHT, SRCCOPY );
		error = GetLastError();

		SelectObject( memDC, oldObject );
		DeleteDC( memDC );
		ReleaseDC(hwnd, hdc);
	}

	if((hwnd == groupBox) && (uMsg == WM_DROPFILES) && (m_active_zone>=0))
	{
		char psz_filename[MAX_PATH];
		char psz_filename_dest[MAX_PATH];
		char msg[MAX_PATH+128];
		DragQueryFile((HDROP)wParam, 0, psz_filename, sizeof(psz_filename));
		int i;
		i = (int)strlen(psz_filename) - 1;
		while(i && psz_filename[i]!='.') i--;
		if(i>0) 
		{
			if(!stricmp(&psz_filename[i],".bmp"))
			{
				CAtmoZoneDefinition *azone = m_pConfig->getZoneDefinition( m_active_zone );
				if(azone)
				{

					sprintf(psz_filename_dest,"%s%s\\zone_%d.bmp",
						m_pDynData->getWorkDir(),
						m_pDynData->getAtmoConnection()->getDevicePath(),
						m_active_zone
						);

					FILE *fp=fopen(psz_filename_dest,"r");
					if(fp) 
					{
						fclose(fp);
						sprintf( msg, Lng->sGradientsText[3] + "%s" + Lng->sGradientsText[4], psz_filename_dest);
						if(MessageBox(m_hDialog, msg ,Lng->sGradientsText[5],MB_ICONQUESTION | MB_YESNO) == IDNO)
							return(r);
					}

					switch(azone->LoadGradientFromBitmap( psz_filename ))
					{
					case ATMO_LOAD_GRADIENT_OK:   
						SetActiveZone( m_active_zone );
						InvalidateRect( groupBox, NULL, false);
						if(!CopyFile( psz_filename, psz_filename_dest, false)) 
						{
							sprintf( msg, Lng->sGradientsText[3] + "%s" + Lng->sGradientsText[6], psz_filename_dest);
							MessageBox(m_hDialog, msg ,Lng->sGradientsText[7], MB_ICONERROR );
						} else
							MessageBox(m_hDialog, Lng->sGradientsText[8],Lng->sGradientsText[9],MB_OK);
						break;
					case ATMO_LOAD_GRADIENT_FILENOTFOND:   
						MessageBox(m_hDialog, Lng->sGradientsText[10],Lng->sGradientsText[7],MB_ICONERROR | MB_OK);
						break;
					case ATMO_LOAD_GRADIENT_FAILED_SIZE:   
						MessageBox(m_hDialog, Lng->sGradientsText[11],Lng->sGradientsText[7],MB_ICONERROR | MB_OK);
						break;
					case ATMO_LOAD_GRADIENT_FAILED_HEADER:   
						MessageBox(m_hDialog, Lng->sGradientsText[12],Lng->sGradientsText[7],MB_ICONERROR | MB_OK);
						break;
					case ATMO_LOAD_GRADIENT_FAILED_FORMAT:   
						MessageBox(m_hDialog, Lng->sGradientsText[13],Lng->sGradientsText[7],MB_ICONERROR | MB_OK);
						break;
					}
				}
				return(r); 
			}
		}
		MessageBox( m_hDialog, Lng->sGradientsText[14],Lng->sGradientsText[7],MB_ICONERROR | MB_OK);
	}
	return(r);
}
Example #3
0
void CAtmoDynData::ReloadZoneDefinitionBitmaps()
{
  int i;
  // suchlogik fuer die Farbverlaufs Bitmaps ...
  // <WorkDir>\hardware\numchannels\zone..0..n.bmp
  // <WorkDir>\hardware\zone..0..n.bmp
  // <WorkDir>\zone..0..n.bmp
  // Automatik Berechnung...
  LockCriticalSection();
  if(!m_pAtmoConnection || !m_pAtmoConfig) {
      UnLockCriticalSection();
      return;
  }

  m_pAtmoConfig->UpdateZoneDefinitionCount();

  CalculateDefaultZones();


  char psz_filename[MAX_PATH];
  CAtmoZoneDefinition *zoneDef;

  sprintf(psz_filename,"%s%s",
                        m_WorkDir,
                        m_pAtmoConnection->getDevicePath()
                );
  CreateDirectory( psz_filename, NULL );

  sprintf(psz_filename,"%s%s\\%dx%dx%d",
                        m_WorkDir,
                        m_pAtmoConnection->getDevicePath(),
                        m_pAtmoConfig->getZonesTopCount(),
                        m_pAtmoConfig->getZonesLRCount(),
                        m_pAtmoConfig->getZonesBottomCount()

               );
  CreateDirectory(psz_filename, NULL );

  // try to load device depended zone definition bitmaps
  for(int zone=0; zone < m_pAtmoConfig->getZoneCount(); zone++)  {
      zoneDef = m_pAtmoConfig->getZoneDefinition(zone);
      if(!zoneDef) continue;

      sprintf(psz_filename,"%s%s\\%dx%dx%d\\zone_%d.bmp",
                        m_WorkDir,
                        m_pAtmoConnection->getDevicePath(),
                        m_pAtmoConfig->getZonesTopCount(),
                        m_pAtmoConfig->getZonesLRCount(),
                        m_pAtmoConfig->getZonesBottomCount(),
                        zone
                );
      i = zoneDef->LoadGradientFromBitmap( psz_filename );
      if(i == ATMO_LOAD_GRADIENT_OK) continue;
      if((i == ATMO_LOAD_GRADIENT_FAILED_SIZE) || (i == ATMO_LOAD_GRADIENT_FAILED_HEADER))
         MessageBox(0,psz_filename,"Failed to load, Check Format, Check Size.",MB_ICONERROR);

      sprintf(psz_filename,"%s%s\\zone_%d.bmp",
                        m_WorkDir,
                        m_pAtmoConnection->getDevicePath(),
                        zone
                );
      i = zoneDef->LoadGradientFromBitmap( psz_filename );
      if(i == ATMO_LOAD_GRADIENT_OK) continue;
      if((i == ATMO_LOAD_GRADIENT_FAILED_SIZE) || (i == ATMO_LOAD_GRADIENT_FAILED_HEADER))
         MessageBox(0,psz_filename,"Failed to load, Check Format, Check Size.",MB_ICONERROR);

      sprintf(psz_filename,"%szone_%d.bmp",
                        m_WorkDir,
                        zone
                );
      i = zoneDef->LoadGradientFromBitmap( psz_filename );
      if(i == ATMO_LOAD_GRADIENT_OK) continue;
      if((i == ATMO_LOAD_GRADIENT_FAILED_SIZE) || (i == ATMO_LOAD_GRADIENT_FAILED_HEADER))
         MessageBox(0,psz_filename,"Failed to load, Check Format, Check Size.",MB_ICONERROR);
  }

  UnLockCriticalSection();
}
Example #4
0
void CAtmoDynData::CalculateDefaultZones()
{
  int i;
  int num_cols_top;
  int num_cols_bottom;
  int num_rows;
  CAtmoZoneDefinition *zoneDef;

  if(!m_pAtmoConfig)
     return;

  m_pAtmoConfig->UpdateZoneDefinitionCount();


  num_cols_top    = m_pAtmoConfig->getZonesTopCount();
  num_cols_bottom = m_pAtmoConfig->getZonesBottomCount();
  num_rows        = m_pAtmoConfig->getZonesLRCount();

  for(int zone=0; zone < m_pAtmoConfig->getZoneCount(); zone++)
  {
     zoneDef = m_pAtmoConfig->getZoneDefinition(zone);
     if(zoneDef)
        zoneDef->Fill(0);
  }


  // the zones will be counted starting from top left - in clockwise order around the display
  // the summary channel will be the last one (in the center)
  i = 0;
  // top zones from left to right
  for(int c=0;c<num_cols_top;c++)
  {
       zoneDef = m_pAtmoConfig->getZoneDefinition(i); i++;
       if(zoneDef) {
          int l = (c * CAP_WIDTH)/num_cols_top;
          int r = ((c+1) * CAP_WIDTH)/num_cols_top;
          zoneDef->FillGradientFromTop( ATMO_MAX( l - CAP_ZONE_OVERLAP, 0) , ATMO_MIN( r + CAP_ZONE_OVERLAP, CAP_WIDTH ) );
       }
  }
  // right zones from top to bottom
  for(int r=0;r<num_rows;r++)
  {
       zoneDef = m_pAtmoConfig->getZoneDefinition(i); i++;
       if(zoneDef) {
          int t = (r * CAP_HEIGHT)/num_rows;
          int b = ((r+1) * CAP_HEIGHT)/num_rows;
          zoneDef->FillGradientFromRight( ATMO_MAX( t - CAP_ZONE_OVERLAP, 0) , ATMO_MIN( b + CAP_ZONE_OVERLAP, CAP_HEIGHT) );
       }
  }
  //  bottom zones from  RIGHT to LEFT!
  for(int c=(num_cols_bottom-1);c>=0;c--)
  {
       zoneDef = m_pAtmoConfig->getZoneDefinition(i); i++;
       if(zoneDef) {
          int l = (c * CAP_WIDTH)/num_cols_bottom;
          int r = ((c+1) * CAP_WIDTH)/num_cols_bottom;
          zoneDef->FillGradientFromBottom( ATMO_MAX( l - CAP_ZONE_OVERLAP, 0 ), ATMO_MIN( r + CAP_ZONE_OVERLAP, CAP_WIDTH ) );
       }
  }
  // left zones from bottom to top!
  for(int r=(num_rows-1);r>=0;r--)
  {
       zoneDef = m_pAtmoConfig->getZoneDefinition(i); i++;
       if(zoneDef)
       {
          int t = (r * CAP_HEIGHT)/num_rows;
          int b = ((r+1) * CAP_HEIGHT)/num_rows;
          zoneDef->FillGradientFromLeft( ATMO_MAX( t - CAP_ZONE_OVERLAP, 0 ), ATMO_MIN( b + CAP_ZONE_OVERLAP, CAP_HEIGHT ) );
       }
  }
  if(m_pAtmoConfig->getZoneSummary())
  {
     // and last the summary zone if requested!
     zoneDef = m_pAtmoConfig->getZoneDefinition(i++);
     if(zoneDef)
        zoneDef->Fill(255);
  }
}
pColorPacket CAtmoColorCalculator::AnalyzeHSV(tHSVColor *HSV_Img)
{
  int i; // counter

  int AtmoSetup_EdgeWeighting  = m_pAtmoConfig->getLiveView_EdgeWeighting();
  int AtmoSetup_WidescreenMode = m_pAtmoConfig->getLiveView_WidescreenMode();
  int AtmoSetup_DarknessLimit  = m_pAtmoConfig->getLiveView_DarknessLimit();
  int AtmoSetup_BrightCorrect  = m_pAtmoConfig->getLiveView_BrightCorrect();
  int AtmoSetup_SatWinSize     = m_pAtmoConfig->getLiveView_SatWinSize();
  int AtmoSetup_NumZones       = m_pAtmoConfig->getZoneCount();
  tHSVColor *temp_Img;

  if(AtmoSetup_NumZones != m_LastNumZones)
  {
     delete[] m_Weight;
     delete[] m_hue_hist;
     delete[] m_windowed_hue_hist;
     delete[] m_most_used_hue_last;
     delete[] m_most_used_hue;
     delete[] m_sat_hist;
     delete[] m_windowed_sat_hist;
     delete[] m_most_used_sat;
     delete[] m_Zone_Weights;
     delete[] m_average_v;
     delete[] m_average_counter;

     m_Weight              = new int[AtmoSetup_NumZones * IMAGE_SIZE];
     m_Zone_Weights        = new int*[AtmoSetup_NumZones];
     for(int i = 0; i < AtmoSetup_NumZones; i++)
         m_Zone_Weights[i] = &m_Weight[i * IMAGE_SIZE];

     m_hue_hist            = new long int[(h_MAX+1) * AtmoSetup_NumZones];
     m_windowed_hue_hist   = new long int[(h_MAX+1) * AtmoSetup_NumZones];

     m_most_used_hue_last  = new int[AtmoSetup_NumZones];
     m_most_used_hue       = new int[AtmoSetup_NumZones];
     memset( m_most_used_hue_last, 0, sizeof(int) * AtmoSetup_NumZones);

     m_sat_hist           = new long int[(s_MAX+1) * AtmoSetup_NumZones];
     m_windowed_sat_hist  = new long int[(s_MAX+1) * AtmoSetup_NumZones];
     m_most_used_sat      = new int[AtmoSetup_NumZones];

     m_average_v         = new long int[AtmoSetup_NumZones];
     m_average_counter   = new int[AtmoSetup_NumZones];

     m_LastNumZones = AtmoSetup_NumZones;
  }


  // calculate only if setup has changed
  if ((AtmoSetup_EdgeWeighting != m_LastEdgeWeighting) ||
      (AtmoSetup_WidescreenMode != m_LastWidescreenMode) ||
      (m_pAtmoConfig->getZonesTopCount() != m_LastLayout_TopCount) ||
      (m_pAtmoConfig->getZonesBottomCount() != m_LastLayout_BottomCount) ||
      (m_pAtmoConfig->getZonesLRCount() !=  m_LastLayout_LRCount) ||
      (m_pAtmoConfig->m_UpdateEdgeWeightningFlag != 0)
     )
  {

      for(i = 0 ;i < AtmoSetup_NumZones; i++) {
          CAtmoZoneDefinition *pZoneDef = m_pAtmoConfig->getZoneDefinition(i);
          if(pZoneDef)
          {
             pZoneDef->UpdateWeighting(m_Zone_Weights[i],
                                                              AtmoSetup_WidescreenMode,
                                                              AtmoSetup_EdgeWeighting);
#ifdef _debug_zone_weight_
             char filename[128];
             sprintf(filename, "zone_%d_gradient_debug.bmp",i);
             pZoneDef->SaveZoneBitmap( filename );
             sprintf(filename, "zone_%d_weight_%d_debug.bmp",i,AtmoSetup_EdgeWeighting);
             pZoneDef->SaveWeightBitmap(filename, m_Zone_Weights[i] );
#endif
          }

     }
     m_pAtmoConfig->m_UpdateEdgeWeightningFlag = 0;

     m_LastEdgeWeighting      = AtmoSetup_EdgeWeighting;
     m_LastWidescreenMode     = AtmoSetup_WidescreenMode;
     m_LastLayout_TopCount    = m_pAtmoConfig->getZonesTopCount();
     m_LastLayout_BottomCount = m_pAtmoConfig->getZonesBottomCount();
     m_LastLayout_LRCount     = m_pAtmoConfig->getZonesLRCount();
  }

  AtmoSetup_DarknessLimit = AtmoSetup_DarknessLimit * 10;


  /***************************************************************************/
  /* Hue                                                                     */
  /***************************************************************************/
  /*----------------------------*/
  /* hue histogram builtup      */
  /*----------------------------*/
  // HSV histogram
  // long int hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1];

  // average brightness (value)
  // m_average_v m_average_counter

  // clean histogram --> calloc
  memset(m_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
  memset(m_average_v, 0, sizeof(long int) * AtmoSetup_NumZones);
  memset(m_average_counter, 0, sizeof(int) * AtmoSetup_NumZones);

  temp_Img = HSV_Img;
  i = 0;
  for (int row = 0; row < CAP_HEIGHT; row++)
  {
    for (int column = 0; column < CAP_WIDTH; column++)
    {
      // forget black bars: perform calculations only if pixel has some luminosity
	  if ((*temp_Img).v > AtmoSetup_DarknessLimit)
      {
        // builtup histogram for the x Zones of the Display
        for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
        {
          // Add weight to channel
         // Weight(zone, pixel_nummer) m_Weight[((zone) * (IMAGE_SIZE)) + (pixel_nummer)]
         // m_hue_hist[zone*(h_MAX+1) + HSV_Img[i].h] += m_Zone_Weights[zone][i] * HSV_Img[i].v;
            m_hue_hist[zone*(h_MAX+1) + (*temp_Img).h] += m_Zone_Weights[zone][i] * temp_Img->v;

            if(m_Zone_Weights[zone][i] > 0) {
               m_average_v[zone] += temp_Img->v;
               m_average_counter[zone]++;
            }

        }
        // calculate brightness average
      }
      temp_Img++;
      i++;
    }
  }

  /*----------------------------*/
  /* hue histogram windowing    */
  /*----------------------------*/
  // windowed HSV histogram
  // long int w_hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1]; -> m_windowed_hue_hist
  // clean windowed histogram
  memset(m_windowed_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
  // steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
  int hue_windowsize = m_pAtmoConfig->getLiveView_HueWinSize();

  for (i = 0; i < h_MAX+1; i++) // walk through histogram [0;h_MAX]
  {
    // windowing from -hue_windowsize -> +hue_windowsize
    for (int mywin = -hue_windowsize; mywin < hue_windowsize+1; mywin++)
    {
      // addressed histogram candlestick
      int myidx = i + mywin;

      // handle beginning of windowing -> roll back
      if (myidx < 0)     { myidx = myidx + h_MAX + 1; }

      // handle end of windowing -> roll forward
      if (myidx > h_MAX) { myidx = myidx - h_MAX - 1; }

      // Apply windowing to all x zones
      for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
      {
        // apply lite triangular window design with gradient of 10% per discrete step
        m_windowed_hue_hist[(zone * (h_MAX+1)) + i] += m_hue_hist[(zone * (h_MAX+1)) + myidx] * ((hue_windowsize+1)-abs(mywin)); // apply window
      }
    }
  }

  /*--------------------------------------*/
  /* analyze histogram for most used hue  */
  /*--------------------------------------*/
  // index of last maximum
  // static int most_used_hue_last[CAP_MAX_NUM_ZONES] = {0, 0, 0, 0, 0}; --> m_most_used_hue_last

  // resulting hue for each channel
  //int most_used_hue[CAP_MAX_NUM_ZONES]; --> m_most_used_hue

  FindMostUsed(AtmoSetup_NumZones, m_most_used_hue, m_windowed_hue_hist);
  for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
  {
    float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue[zone]];
    if (percent > 0.93f) // less than 7% difference?
        m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
     else
        m_most_used_hue_last[zone] = m_most_used_hue[zone];
  }

  /*
  memset(m_most_used_hue, 0, sizeof(int) * AtmoSetup_NumZones);

  for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
  {
    long int value = 0;
    for (i = 0; i < h_MAX+1; i++) // walk through histogram
    {
      long int tmp = m_windowed_hue_hist[ (zone * (h_MAX+1)) + i ];
      if (tmp > value) // if new value bigger then old one
      {
        m_most_used_hue[zone] = i;     // remember index
        value = tmp; // w_hue_hist[zone][i]; // and value
      }
    }

    float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)value;
    if (percent > 0.93f) // less than 7% difference?
    {
      m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
    }

    m_most_used_hue_last[zone] = m_most_used_hue[zone]; // save current index of most used hue
  }
  */

  /***************************************************************************/
  /* saturation                                                              */
  /***************************************************************************/
  // sat histogram
  // long int sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1];  -> m_sat_hist
  // hue of the pixel we are working at
  int pixel_hue = 0;
  // clean histogram
  memset(m_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);

  /*--------------------------------------*/
  /* saturation histogram builtup         */
  /*--------------------------------------*/
  i = 0;
  temp_Img = HSV_Img;
  for (int row = 0; row < CAP_HEIGHT; row++)
  {
    for (int column = 0; column < CAP_WIDTH; column++)
    {
      // forget black bars: perform calculations only if pixel has some luminosity
	  if ((*temp_Img).v > AtmoSetup_DarknessLimit)
      {
        // find histogram position for pixel
        pixel_hue = (*temp_Img).h;

        // TODO:   brightness calculation(if we require it some time)

        for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
        {
          // only use pixel for histogram if hue is near most_used_hue
          if ((pixel_hue > m_most_used_hue[zone] - hue_windowsize) &&
              (pixel_hue < m_most_used_hue[zone] + hue_windowsize))
          {
            // build histogram
            // sat_hist[channel][HSV_Img[i].s] += Weight[i].channel[channel] * HSV_Img[i].v;
            m_sat_hist[zone * (s_MAX+1) + (*temp_Img).s ] += m_Zone_Weights[zone][i] * (*temp_Img).v;

          }
        }
      }
      i++;
      temp_Img++;
    }
  }

  /*--------------------------------------*/
  /* saturation histogram windowing       */
  /*--------------------------------------*/
   // windowed HSV histogram
   // long int w_sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1]; --> m_windowed_sat_hist
   // clean windowed histogram
   memset(m_windowed_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);
   // steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
   int sat_windowsize = AtmoSetup_SatWinSize;

   // walk through histogram [0;h_MAX]
   for (i = 0; i < s_MAX + 1; i++)
   {
     // windowing from -hue_windowsize -> +hue_windowsize
     for (int mywin = -sat_windowsize; mywin < sat_windowsize+1; mywin++)
     {
       // addressed histogram candlestick
       int myidx = i + mywin;

       // handle beginning of windowing -> roll back
       if (myidx < 0)     { myidx = myidx + s_MAX + 1; }

       // handle end of windowing -> roll forward
       if (myidx > h_MAX) { myidx = myidx - s_MAX - 1; }

       for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
       {
         /*
            apply lite triangular window design with
            gradient of 10% per discrete step
         */
         /*
         w_sat_hist[channel][i] += sat_hist[channel][myidx] *
                                  ((sat_windowsize+1)-abs(mywin)); // apply window
         */
         m_windowed_sat_hist[zone * (s_MAX+1) + i] += m_sat_hist[zone* (h_MAX+1) + myidx] *
                                  ((sat_windowsize+1)-abs(mywin)); // apply window
       }
     }
   }

  /*--------------------------------------*/
  /* analyze histogram for most used sat  */
  /*--------------------------------------*/
   // resulting sat (most_used_hue) for each channel
  // int most_used_sat[CAP_MAX_NUM_ZONES];->m_most_used_sat

  FindMostUsed(AtmoSetup_NumZones, m_most_used_sat, m_windowed_sat_hist);
  /*
  memset(m_most_used_sat, 0, sizeof(int) * AtmoSetup_NumZones);

  for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
  {
    int value = 0;
    // walk trough histogram
    for (i = 0; i < s_MAX+1; i++)
    {
      // if new value bigger then old one
      int tmp = m_windowed_sat_hist[zone * (s_MAX+1) + i];
      // if (w_sat_hist[channel][i] > value)
      if (tmp > value)
      {
        // remember index
        m_most_used_sat[zone] = i;
        // and value
        value = tmp;
      }
    }
  }
  */


  /*----------------------------------------------------------*/
  /* calculate average brightness within HSV image            */
  /* uniform Brightness for all channels is calculated        */
  /*----------------------------------------------------------*/
  /* code integrated into "hue histogram builtup" to save some looping time!
  int l_counter = 0;
  // average brightness (value)
  long int value_avg = 0;
  i = 0;
  for (int row = 0; row < CAP_HEIGHT; row++)
  {
    for (int column = 0; column < CAP_WIDTH; column++)
    {
      // find average value: only use bright pixels for luminance average
	  if (HSV_Img[i].v > AtmoSetup_DarknessLimit)
      {
        // build brightness average
        value_avg += HSV_Img[i].v;
        l_counter++;
      }
      i++;
    }
  }
  // calculate brightness average
  if (l_counter > 0) { value_avg = value_avg / l_counter; }
    else { value_avg = AtmoSetup_DarknessLimit; }

  */


  /*----------------------------*/
  /* adjust and copy results    */
  /*----------------------------*/
  tHSVColor hsv_pixel;
  // storage container for resulting RGB values
  pColorPacket output_colors;
  AllocColorPacket(output_colors, AtmoSetup_NumZones);

  // adjust brightness
//  int new_value = (int) ((float)value_avg * ((float)AtmoSetup_BrightCorrect / 100.0));
//  if (new_value > 255) new_value = 255;  // ensure brightness isn't set too high
//  hsv_pixel.v = (unsigned char)new_value;

  /*
  // calculate brightness average
  for(int zone = 0; zone < AtmoSetup_NumZones; zone++) {
      if(m_average_counter[zone] > 0)
          m_average_v[zone] = m_average_v[zone] / m_average_counter[zone]
      else
          m_average_v[zone] = AtmoSetup_DarknessLimit;
  }

  */

  for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
  {
    if(m_average_counter[zone] > 0)
       m_average_v[zone] = m_average_v[zone] / m_average_counter[zone];
    else
       m_average_v[zone] = AtmoSetup_DarknessLimit;

    m_average_v[zone] = (int)((float)m_average_v[zone] * ((float)AtmoSetup_BrightCorrect / 100.0));

    hsv_pixel.v = (unsigned char)ATMO_MAX(ATMO_MIN(m_average_v[zone],255),0);
    hsv_pixel.h = m_most_used_hue[zone];
    hsv_pixel.s = m_most_used_sat[zone];

    // convert back to rgb
    output_colors->zone[zone] = HSV2RGB(hsv_pixel);
  }


  return output_colors;
}