/* bluebox distributor
 * version 0.3.2 date 2007-07-18
 * Copyright (C) 2006-2007 Stefan Schuermans <stefan@blinkenarea.org>
 * Copyleft: GNU public license V2.0 - http://www.gnu.org/copyleft/gpl.html
 * a BlinkenArea project - http://www.blinkenarea.org/
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <netinet/in.h>

#include <BlinkenLib.h>

#include "bd_fmt.h"
#include "protocols.h"

//mapping from grayscale values to PWM values
//may only contain values fomr 0x00 to 0x7F
unsigned char gray2pwm[0x100];

//initialize mapping from gayscale values to PWM values
void gray2pwm_init( double base, double spread, double gamma )
{
  int i;
  for( i = 0; i < 0x100; i++ )
  {
    double val = (double)i / (double)0xFF; // 0x00 ... 0xFF ---> 0.0 ... 1.0
    val = val * spread + base; // base brightness and brighness spread
    if( val < 0.0 ) val = 0.0; if( val > 1.0 ) val = 1.0; // clamp value to valid range: 0.0 ... 1.0
    val = pow( val, gamma ); // gamma correction
    gray2pwm[i] = (unsigned char)((double)0x7F * val + 0.5); // 0.0 ... 0.1 ---> 0x00 .. 0x7F
  }
}

//processs a recevied datagram
//p_out_buffers must point to an array of dev_cnt output buffers
//  every output buffer must be of size (1 + pix_cnt) * ser_cnt
//  pixels start at offset 1 in output buffers
//  every pixel in output buffer is encoded with 7 bit (i.e. 0..127)
//returns 1 on success, 0 on error
int proto_datagram( unsigned char * p_datagram, unsigned int datagram_len,
                    st_bd_fmt * p_bd_fmt, unsigned char * * p_out_buffers )
{
  etBlinkenProto proto;
  stBlinkenFrame * p_frame;
  unsigned int y, x;
  st_bd_fmt_pix * p_bd_fmt_pix;
  unsigned char value;

  //parse frame in datagram
  p_frame = BlinkenFrameFromNetwork( (char *)p_datagram, datagram_len, &proto );
  if( p_frame == NULL )
    return 0;

  //resize frame to <width>x<height>-1/128
  BlinkenFrameResize( p_frame, p_bd_fmt->height, p_bd_fmt->width, 1, 255 );

  //write pixels into output buffer
  for( y = 0; y < p_bd_fmt->height; y++ )
  {
    for( x = 0; x < p_bd_fmt->width; x++ )
    {
      p_bd_fmt_pix = &p_bd_fmt->pixels[y][x];
      if( p_bd_fmt_pix->valid )
      {
        value = BlinkenFrameGetPixel( p_frame, y, x, 0 );
        p_out_buffers[p_bd_fmt_pix->dev_no][p_bd_fmt_pix->out_buf_ofs] = gray2pwm[value];
      }
    }
  }

  return 1;
}
