#include <stddef.h>
#include "livido.h"

// Implementation of very simple fade plugin


// Here is the structure of paramters that will be used in the plugin:
// This structure is later 'described' in param_in_templates
typedef struct { 
	lvd_type_number fade;  // fade value between 0.0 and 1.0
} parameters_structure_t;

// GOOD PRACTICE: don't even think about using multiline options for stringlists!

// Default, minmal and maximal values of parameters
// minimum and maximum for stringlists are currently ignored
parameters_structure_t values_minimum = {.fade = 0.0 };
parameters_structure_t values_maximum = {.fade = 1.0 };
parameters_structure_t values_default = {.fade = 0.3 };

// Describe the above structure
// the description and the structure must match 1:1 in order
// for plugin to work properly

livido_parameter_template_t param_in_templates[] = {
	{
		.name = "Fade value",
		.description = "1.0 image is shown, 0.0 image is not shown",
		.hint = "",
		.type = LVD_PARAM_NUMBER,	      ///< the parameter type
		.offset = offsetof(parameters_structure_t, fade),
		.decimals = 2,
		.step_size = 0.01,
		.choice_list = NULL,
		.flags = LVD_PARAM_FLAG_KEYFRAMED
	}, 
	LIVIDO_PARAM_END
};

livido_parameter_template_t param_out_templates[] = { LIVIDO_PARAM_END };
			
// this plugin uses the same input and output palette
// therefore we have just one definition and use it for both in and out channels
livido_palette_t plugin_io_palette[] = {	
	LVD_PALETTE_RGB565,
	LVD_PALETTE_RGB888, 
	LVD_PALETTE_RGBA8888,
	LVD_PALETTE_RGBX8888, 
	LVD_PALETTE_YUV888, 
	LVD_PALETTE_YUVA8888, 
	LVD_PALETTE_END
};
					
					
// this plugin will have one input and one output channel, both will have to be of the same size and palette
livido_channel_template_t plugin_in_channels[] = {{
	.name = "Input 1",
	.flags = 0,
	.palettes = plugin_io_palette,
	.same_as = 0, // this is specified at output channels
	.width = 0,
	.height = 0,
	},
	LIVIDO_CHANNEL_TEMPLATE_END
};

livido_channel_template_t plugin_out_channels[] = {{
	.name = "Output 1",
	.flags = LIVIDO_CHNLTMPL_SAME_AS_SIZE | LIVIDO_CHNLTMPL_SAME_AS_PALETTE,
	.palettes = plugin_io_palette,
	.same_as = 1,
	.width = 0,
	.height = 0,
	},
	LIVIDO_CHANNEL_TEMPLATE_END
};
			



// forward declarations of functions so they can be used when crating livido_calss_t
int init_instance (livido_instance_t* my_instance);
int deinit_instance (livido_instance_t* my_instance);
int process_frame (livido_instance_t* instance, livido_timecode_t timecode, livido_frame_t *in,  livido_frame_t *out);
livido_instance_template_t  *livido_setup();

livido_instance_template_t template_fade[] = {{
	.name = "Fade plugin",
	.author = "Andraz Tori <andraz.tori1@guest.arnes.si>",
	.description = "Fades intensity or A or Y channel",
	.licence = "Public domain",
	.version = LIVIDO_HEADER_VERSION,
	.property = LVD_PROPERTY_REALTIME | LVD_PROPERTY_CAN_DO_SCALED | LVD_PROPERTY_CAN_DO_INPLACE,
	.in_parameter_templates = param_in_templates,
	.out_parameter_templates = param_out_templates,
	.params_in_min = &values_minimum,
	.params_in_max = &values_maximum,
	.params_in_def = &values_default,
	.params_in_sets = NULL,
	.in_channel_templates = plugin_in_channels,
	.out_channel_templates = plugin_out_channels,
	.init = init_instance,
	.deinit = deinit_instance,
	.process = process_frame,
	.interpolate_parameters = NULL
	},
	LIVIDO_INSTANCE_TEMPLATE_END
};


// we don't need to do anything... wierd ah? :)
livido_instance_template_t  *livido_setup() {
	LIVIDO_FILL_SIZES(template_fade[0]);
	return (&template_fade[0]);	
}


int init_instance (livido_instance_t* my_instance) {
	my_instance->internal = NULL; // this plugin keeps no internal state
	return 0;
}

int deinit_instance (livido_instance_t* my_instance) {
	// we would do cleanup and freeing of ->internal here, but we have nothing to do[A
	return 0;
}

int process_frame (		livido_instance_t* instance,
				livido_timecode_t timecode,
				livido_frame_t *in, 
				livido_frame_t *out)
{
	parameters_structure_t *myparams = (parameters_structure_t *) instance->params_in;
	
	float fade = myparams->fade;
	
	// instead of instance->in_channels we could also use in[0].channel...
	livido_palette_t pal = instance->in_channels[0].palette;
	int width = instance->in_channels[0].width;
	int height = instance->in_channels[0].height;
	int rowstride_in = instance->in_channels[0].rowstrides[0];    // This has to be the same because both
	int rowstride_out = instance->in_channels[0].rowstrides[0];   // same_size and same_palette are set
								// but ... if this is not the case, you have to have two
								
	char *in_frame = in[0].pixel_data[0];
	char *out_frame = out[0].pixel_data[0];
	// we could check here if we are doing inplace, but there is no need since rutine is the same for both
	
	unsigned char *in_values, *out_values;
	int i,j;
	// Ok lets do the processing, this is highly non-optimal... just not to have too much code
	for (i = 0; i< height; i++) 
	{
		in_values = (unsigned char*) in_frame + i * rowstride_in;
		out_values = (unsigned char*) out_frame + i * rowstride_out;
		for (j = 0; j< width; j++) 
		{
			if (pal == LVD_PALETTE_RGB565) 
			{
				unsigned short iv=*(unsigned short *)in_values;
				unsigned char r=(iv>>11)<<3,g=(iv>>3)&0xfc,b=(iv&0x1f)<<3;
				r*=fade;
				g*=fade;
				b*=fade;
				*((unsigned short *)out_values)=((r>>3)<<11)|((g>>2)<<5)|(b>>3);
				out_values+=2;
				in_values+=2;
			} else
			if (pal == LVD_PALETTE_RGB888) 
			{
				out_values[0] = in_values[0] * fade;
				out_values[1] = in_values[1] * fade;
				out_values[2] = in_values[2] * fade;
				out_values += 3; in_values +=3;
			} else
			if (pal == LVD_PALETTE_RGBA8888) 
			{
				out_values[0] = in_values[0];
				out_values[1] = in_values[1];
				out_values[2] = in_values[2];
				out_values[3] = in_values[3] * fade;
				out_values += 4; in_values +=4;
			} else
			if (pal == LVD_PALETTE_RGBX8888) 
			{
				out_values[0] = in_values[0] * fade;
				out_values[1] = in_values[1] * fade;
				out_values[2] = in_values[2] * fade;
				out_values += 4; in_values +=4;
			} else
			if (pal == LVD_PALETTE_YUV888) 
			{
				out_values[0] = in_values[0] * fade;
				out_values[1] = in_values[1];
				out_values[2] = in_values[2];
				out_values += 3; in_values +=3;
			} else
			if (pal == LVD_PALETTE_YUVA8888) 
			{
				out_values[0] = in_values[0];
				out_values[1] = in_values[1];
				out_values[2] = in_values[2];
				out_values[3] = in_values[3] * fade;
				out_values += 4; in_values +=4;
			};
		}
	}
	return 0;
}

