/* Copyright (C) 2003 Damir Zucic */

/*=============================================================================

				blur_main_window.c

Purpose:
	Blur the main window free area.  The pixels from the rectangular
	area defined by blur_width and blur_height are used to calculate
	the average RGB values,  to replace the color of the pixel which
	is in the center of the rectangular area.

Input:
	(1) Pointer to RuntimeS structure.
	(2) Pointer to GUIS structure.
	(3) Pointer to NearestAtomS structure.
	(4) The number of pixels in the main window free area.

Output:
	(1) The image in the main window free are will be modified.
	(2) Return value.

Return value:
	(1) Positive on success.
	(2) Negative on failure.

Notes:
	(1) Indentation is exceptionally four spaces.

	(2) Blur  will not  affect labels,  tags,  titles and  the small
	    coordinate system in the top left corner.

========includes:============================================================*/

#include <stdio.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>

#include "defines.h"
#include "typedefs.h"

/*======blur the main window free area:======================================*/

size_t BlurMainWindow_ (RuntimeS *runtimeSP, GUIS *guiSP,
			NearestAtomS *nearest_atomSP, size_t pixelsN)
{
static unsigned long	ulong_red_mask, ulong_green_mask, ulong_blue_mask;
int			free_area_width, free_area_height;
int			blur_width, blur_half_width;
int			blur_height, blur_half_height;
int			row_startI, row_endI, column_startI, column_endI;
int			screen_x0, screen_y0;
static long double	ldouble_new_red, ldouble_new_green, ldouble_new_blue;
int			mixed_pixelsN;
int			rowI, columnI;
int			screen_x1, screen_y1;
int			pixelI;
NearestAtomS		*curr_pixelSP;
unsigned long		old_colorID;
static unsigned long	ulong_old_red, ulong_old_green, ulong_old_blue;
static long double	ldouble_old_red, ldouble_old_green, ldouble_old_blue;
long double		reciprocal_mixed_pixelsN;
static unsigned long	ulong_new_red, ulong_new_green, ulong_new_blue;
unsigned long		new_colorID;

/* Copy the color masks: */
ulong_red_mask   = guiSP->visual_infoS.red_mask;
ulong_green_mask = guiSP->visual_infoS.green_mask;
ulong_blue_mask  = guiSP->visual_infoS.blue_mask;

/* Copy the width and height of the main window free area: */
free_area_width  = (int) guiSP->main_win_free_area_width;
free_area_height = (int) guiSP->main_win_free_area_height;

/* Copy and check the width and height of the blur rectangle: */
blur_width = runtimeSP->blur_width;
if (blur_width <= 0) return -1;
blur_half_width = (blur_width - 1) / 2;
blur_height = runtimeSP->blur_height;
if (blur_height <= 0) return -2;
blur_half_height = (blur_height - 1) / 2;

/* Prepare start and end indices required to scan blur rectangle: */
row_startI = -blur_half_width;
row_endI = row_startI + blur_width - 1;
column_startI = -blur_half_height;
column_endI = column_startI + blur_height - 1;

/* Vertical scan of the main window free area: */
for (screen_x0 = 0; screen_x0 < free_area_width; screen_x0++)
    {
    /* Horizontal scan of the main window free area: */
    for (screen_y0 = 0; screen_y0 < free_area_height; screen_y0++)
	{
	/* Reset  the variables  which store the */
	/* new color components as long doubles: */
	ldouble_new_red   = 0.0;
	ldouble_new_green = 0.0;
	ldouble_new_blue  = 0.0;

	/* Reset the counter  which counts  the pixels */
	/* used to calculate the new color components: */
	mixed_pixelsN = 0;

	/* Vertical scan of the blur rectangle: */
	for (rowI = row_startI; rowI <= row_endI; rowI++)
	    {
	    /* Prepare and check the vertical position of the current pixel: */
	    screen_y1 = screen_y0 + rowI;
	    if (screen_y1 < 0) continue;
	    if (screen_y1 >= free_area_height) continue;

	    /* Horizontal scan of the blur rectangle: */
	    for (columnI = column_startI; columnI <= column_endI; columnI++)
		{
		/* Prepare and check the horizontal */
		/* position  of the  current pixel: */
		screen_x1 = screen_x0 + columnI;
		if (screen_x1 < 0) continue;
		if (screen_x1 >= free_area_width) continue;

		/* Prepare and check the pixel index: */
		pixelI = free_area_width * screen_y1 + screen_x1;
		if (pixelI >= (int) pixelsN) continue;

		/* Prepare the pointer to the current pixel: */
		curr_pixelSP = nearest_atomSP + pixelI;

		/* Copy the color ID of the current pixel: */
		old_colorID = curr_pixelSP->colorID;

		/* Extract the old color components: */
		ulong_old_red   = old_colorID & ulong_red_mask;
		ulong_old_green = old_colorID & ulong_green_mask;
		ulong_old_blue  = old_colorID & ulong_blue_mask;

		/* Convert unsigned long values to long double values: */
		ldouble_old_red   = (long double) ulong_old_red;
		ldouble_old_green = (long double) ulong_old_green;
		ldouble_old_blue  = (long double) ulong_old_blue;

		/* Add these values to the corresponding totals: */
		ldouble_new_red   += ldouble_old_red;
		ldouble_new_green += ldouble_old_green;
		ldouble_new_blue  += ldouble_old_blue;

		/* Update the pixel counter: */
		mixed_pixelsN++;
		}
	    }
	/* Check the number of pixels which were mixed and */
	/* calculate the reciprocal value  if appropriate: */
	if (mixed_pixelsN <= 0) continue;
	reciprocal_mixed_pixelsN = 1.0 / (long double) mixed_pixelsN;

	/* Prepare and check the index of the pixel */
	/* in  the middle  of  the blur  rectangle: */
	pixelI = free_area_width * screen_y0 + screen_x0;
	if (pixelI >= (int) pixelsN) continue;

	/* Prepare the pointer to the pixel in */
	/* the middle of  the blur  rectangle: */
	curr_pixelSP = nearest_atomSP + pixelI;

	/* Calculate the average values of color componets: */
	ldouble_new_red   *= reciprocal_mixed_pixelsN;
	ldouble_new_green *= reciprocal_mixed_pixelsN;
	ldouble_new_blue  *= reciprocal_mixed_pixelsN;

	/* Convert the long double values to unsigned long values: */
	ulong_new_red   = (unsigned long) ldouble_new_red;
	ulong_new_green = (unsigned long) ldouble_new_green;
	ulong_new_blue  = (unsigned long) ldouble_new_blue;

	/* Combine the unsigned long values with color masks: */
	ulong_new_red   &= ulong_red_mask;
	ulong_new_green &= ulong_green_mask;
	ulong_new_blue  &= ulong_blue_mask;

	/* Combine the color components into a single color ID: */
	new_colorID = ulong_new_red | ulong_new_green | ulong_new_blue;

	/* Store  the new color ID to  the NearestAtomS */
	/* structure associated with the central pixel: */
	curr_pixelSP->colorID = new_colorID;

	/* Redraw the current pixel: */
	XSetForeground (guiSP->displaySP, guiSP->theGCA[0], new_colorID);
	XDrawPoint (guiSP->displaySP, guiSP->main_winS.ID,
		    guiSP->theGCA[0], screen_x0, screen_y0);
	}
    }

/* Return positive value on success: */
return 1;
}

/*===========================================================================*/


