/*******************************************************************
                          resize module
 *******************************************************************/
#define RESIZE_C
#include "resize.h"

#include <math.h>
#include <stdlib.h>
#include <string.h>

void h_resize(FRAME *in, FRAME *out, H_RESIZE_PARAMETER *prm);
H_RESIZE_PARAMETER *create_h_resize_parameter(int original_width, int result_width);
void release_h_resize_parameter(H_RESIZE_PARAMETER *prm);

static void component_h_resize(unsigned char *in, unsigned char *out, int width, int height, H_RESIZE_PARAMETER *prm);

/*******************************************************************/
void h_resize(FRAME *in, FRAME *out, H_RESIZE_PARAMETER *prm)
{
	component_h_resize(in->y, out->y, in->width, in->height, prm);
	component_h_resize(in->u, out->u, in->width, in->height, prm);
	component_h_resize(in->v, out->v, in->width, in->height, prm);

	return;
}

H_RESIZE_PARAMETER *create_h_resize_parameter(int original_width, int result_width)
{
	double work;
	double distance;
	int i,j;

	H_RESIZE_PARAMETER *r;

	r = (H_RESIZE_PARAMETER *)malloc(sizeof(H_RESIZE_PARAMETER));
	if(r == NULL){
		return NULL;
	}
	r->width = result_width;

	r->weight = (int *)malloc(sizeof(int)*result_width*4);
	if(r->weight == NULL){
		free(r);
		return NULL;
	}

	r->coordinates = (int *)malloc(sizeof(int)*result_width*4);
	if(r->coordinates == NULL){
		free(r->weight);
		free(r);
		return NULL;
	}

	for(i=0;i<result_width;i++){

		work = original_width * i;
		work /= result_width;

		r->coordinates[i*4+1] = (int)work;
		r->coordinates[i*4+0] = r->coordinates[i*4+1] - 1;
		if(r->coordinates[i*4+0] < 0){
			r->coordinates[i*4+0] = 0;
		}
		for(j=0;j<2;j++){
			r->coordinates[i*4+2+j] = r->coordinates[i*4+1+j] + 1;
			if(r->coordinates[i*4+2+j] >= original_width){
				r->coordinates[i*4+2+j] = original_width - 1;
			}
		}

		work -= r->coordinates[i*4+1];
		distance = work + 1;
		r->weight[i*4+0] = (4.0 - 8.0 * distance + 5.0 * pow(distance, 2) - pow(distance, 3)) * (1 << 16);
		distance = work;
		r->weight[i*4+1] = (1.0 - 2.0 * pow(distance, 2) + pow(distance, 3)) * (1 << 16);
		distance = 1 - work;
		r->weight[i*4+2] = (1.0 - 2.0 * pow(distance, 2) + pow(distance, 3)) * (1 << 16);
		distance = 2 - work;
		r->weight[i*4+3] = (4.0 - 8.0 * distance + 5.0 * pow(distance, 2) - pow(distance, 3)) * (1 << 16);
	}

	return r;
}

void release_h_resize_parameter(H_RESIZE_PARAMETER *prm)
{
	if(prm){
		if(prm->weight){
			free(prm->weight);
		}
		if(prm->coordinates){
			free(prm->coordinates);
		}
		free(prm);
	}
}
	   
static void component_h_resize(unsigned char *in, unsigned char *out, int width, int height, H_RESIZE_PARAMETER *prm)
{
	int i;
	int work;
	int x,y;

	for(y=0;y<height;y++){
		for(x=0;x<prm->width;x++){
			work = 0;
			for(i=0;i<4;i++){
				work += in[prm->coordinates[x*4+i]] * prm->weight[x*4+i];
			}
			out[x] = uchar_clip_table[UCHAR_CLIP_TABLE_OFFSET+(work>>16)];
		}
		in += width;
		out += prm->width;
	}

	return;
}


