/*****************************************************************************
* Output filter routines, performing supersampling filtering.		     *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Bassarab Dmitri & Plavnik Michael       Ver 0.2, Apr. 1995    *
*****************************************************************************/

#include "program.h"
#include "filt.h"
#include "debug.h"

#define SUPER_SIZE 3

static RealType Filter[SUPER_SIZE][SUPER_SIZE], GlblWeight;

/*****************************************************************************
* DESCRIPTION:                                                               M
*    Routine to setup internal module data structures before any antialias   M
*    processing could be done. Assumes SUPER_SIZE constant to define super-  M
*    sampling size and "FilterName" to define known to the program filter    M
*                                                                            *
* PARAMETERS:                                                                M
*   None                                                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   SetupAntialias, antialias, AntialiasLine, Utah filter package            M
*****************************************************************************/
void SetupAntialias(void)
{
    int i, j;
    RealType x, y, r;
    Filt *f;

    if (!Options.FilterName)
        return;
    if (!(f = filt_find(Options.FilterName))) {
        f = filt_find(Options.FilterName = "sinc");
        fprintf(stderr,
		"Warning: unknown filter name, %s used\n",
		Options.FilterName);
    }
    Options.XSize *= SUPER_SIZE;
    Options.YSize *= SUPER_SIZE;
    if (f -> windowme) {
        f -> supp = 1;
        f = filt_window(f, "hanning");
    }
    r = f -> supp / M_SQRT2;
    for (GlblWeight = i = 0; i < SUPER_SIZE; i++) {
        y = (i + 1) * 2 * r / (SUPER_SIZE + 1) - r;
        for (j = 0; j < SUPER_SIZE; j++) {
            x = (j + 1) * 2 * r / (SUPER_SIZE + 1) - r;
            GlblWeight += Filter[i][j] = filt_func(f, (sqrt(SQR(y) + SQR(x))));
        }
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*    Performs supersampling antialias algorithm on a z-buffer scan line,     M
*    using filter data structures established by "SetupAntialias" routine.   M
*    If client doesn't need antialias it should set "FilterName" to NULL     M
*    in which case color data is passed throw to the output routine (always  M
*    in standard RGB format and alpha data which is weight of background in  M
*    super pixel.                                                            M
*    Assumes SUPER_SIZE to be defined as supersampling size, SetupAntialias  M
*    to be called before.                                                    M
*                                                                            *
* PARAMETERS:                                                                M
*   z:        Array of z-buffer scan line data, contains RGB color data as   M
*             as specified in ZSlot structure description ([0, 1] format)    M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AntialiasLine, antialias, supersampling, alpha channel, SetupAntialias   M
*****************************************************************************/
void AntialiasLine(ZSlotStruct *z)
{
    static ByteType
	*Alpha = NULL;
    static ColorType *Pool;
    static PixelStruct *Pixels;
    static int
	Counter = 0,
	y = 0;
    int x, s;

    if (!Alpha) {
        Alpha = MALLOC(ByteType,
		       Options.FilterName ? Options.XSize / SUPER_SIZE
		                          : Options.XSize);
        Pixels = MALLOC(PixelStruct,
			Options.FilterName ? Options.XSize / SUPER_SIZE
			                   : Options.XSize);
        if (Options.FilterName)
            Pool = MALLOC(ColorType, Options.XSize / SUPER_SIZE);
    }
    if (Options.FilterName) {
        if (!Counter) {
            ZAP_MEM(Alpha, sizeof(ByteType) * Options.XSize / SUPER_SIZE);
            for (x = 0; x < Options.XSize / SUPER_SIZE; x++)
                PT_CLEAR(Pool[x]);
        }
        for (x = 0; x < Options.XSize / SUPER_SIZE; x++)
            for (s = 0; s < SUPER_SIZE; s++) {
                ZSlotStruct
		    *p = &z[x * SUPER_SIZE + s];

                Alpha[x] += (p -> bg.flat != NULL);
                PT_SCALE(p -> color, Filter[Counter][s]);
                PT_ADD(Pool[x], Pool[x], p -> color);
            }
        if (++Counter == SUPER_SIZE) {
            Counter = 0;
            for (x = 0; x < Options.XSize / SUPER_SIZE; x++) {
	        RealType
		    W256 = 0xff / GlblWeight;

                Alpha[x] = (ByteType) (Alpha[x] * W256);
                Pixels[x].r = (unsigned char) (Pool[x][R] * W256);
                Pixels[x].g = (unsigned char) (Pool[x][G] * W256);
                Pixels[x].b = (unsigned char) (Pool[x][B] * W256);
            }
	    SCANLINE_MESSAGE(y++);
            ImagePutLine(Alpha, Pixels);
        }
    }
    else {
	if (Options.ZDepth)
	    for (x = 0; x < Options.XSize; x++) {
	        char
		    *RGBA = (char *)&(z[x].bg.value.z);

		Pixels[x].r = RGBA[R];
		Pixels[x].g = RGBA[G];
		Pixels[x].b = RGBA[B];
		Alpha[x] = RGBA[B+1];
	    }
	else
	    for (x = 0; x < Options.XSize; x++) {
                Alpha[x] = (z[x].bg.flat != NULL) * 0xff;
		Pixels[x].r = (unsigned char) (z[x].color[R] * 0xff);
		Pixels[x].g = (unsigned char) (z[x].color[G] * 0xff);
		Pixels[x].b = (unsigned char) (z[x].color[B] * 0xff);
	    }
	SCANLINE_MESSAGE(y++);
        ImagePutLine(Alpha, Pixels);
    }
}
