#ifndef lint
static char *sccsid = "@(#)pattern.c	1.2 (Steve Hill) 3/9/90";
#endif

/* pattern.c
 *
 * Routine to create copy and free the various forms of pattern.
 *
 */

#include <stdio.h>

#include "basetype.h"
#include "cartesian.h"
#include "malloc.h"
#include "error.h"
#include "matrix.h"
#include "point.h"
#include "vector.h"
#include "indexlist.h"
#include "ray.h"
#include "colour.h"
#include "list.h"
#include "surface.h"
#include "quadric.h"
#include "solid.h"
#include "bbox.h"
#include "bitmap.h"
#include "pattern.h"


/* NewPattern
 *
 * Private function to allocate a pattern.
 */

pattern_t *
NewPattern()
{
	pattern_t	*pattern;

	pattern = (pattern_t *) malloc(sizeof(pattern_t));
	if (pattern == PatternNull)
		FatalError(__FILE__, __LINE__, "NewPattern: out of memory");

	return(pattern);
}


/* Pattern
 *
 * Allocate and initialise a pattern structure.
 */

pattern_t *
Pattern(description, function)
description_t	*description;
void		(*function)();
{
	pattern_t	*pattern;

	pattern = NewPattern();

	pattern->description = description;
	pattern->function    = function;
	pattern->matrix      = MatrixId(4);
	pattern->point       = PointZero;

	return(pattern);
}


/* PatternFree
 *
 * Free a pattern structure and all sub-structures.
 */

void
PatternFree(pattern)
pattern_t	*pattern;
{
	DescriptionFree(pattern->description);
	MatrixFree(pattern->matrix);
	PointFree(pattern->point);
	free((char *) pattern);
}


/* PatternCopy
 *
 * Copy a pattern structure and sub-components.
 */

pattern_t *
PatternCopy(pattern)
pattern_t	*pattern;
{
	pattern_t	*new;

	if (pattern == PatternNull)
		return(PatternNull);

	new = NewPattern();

	new->description = DescriptionCopy(pattern->description);
	new->function    = pattern->function;
	new->matrix      = MatrixCopy(pattern->matrix);
	new->point       = PointCopy(pattern->point);

	return(new);
}


/* PatternTransform
 *
 * Transform a pattern.
 */

pattern_t *
PatternTransform(pattern, matrix)
pattern_t	*pattern;
matrix_t	*matrix;
{
	if (pattern != PatternNull)
		MatrixMul(pattern->matrix, matrix, pattern->matrix);

	return(pattern);
}

/* PatternPrint
 *
 * Print a pattern to a file.
 */

void
PatternPrint(file, pattern)
FILE	*file;
pattern_t	*pattern;
{
	if (pattern == PatternNull)
	{
		fprintf(file, "Null Pattern\n");
		return;
	}

	DescriptionPrint(file, pattern->description);
	MatrixPrint(file, pattern->matrix);
}


/* NewDescription
 *
 * Private function to allocate a description structure.
 */

static
description_t *
NewDescription()
{
	description_t	*description;

	description = (description_t *) malloc(sizeof(description_t));
	if (description == DescriptionNull)
		FatalError(__FILE__, __LINE__, "NewDescription: out of memory");

	return(description);
}


/* Description
 *
 * Allocate and initialise a description.
 * The pointer should point to a structure of the appropriate type.
 */

description_t *
Description(sort, ptr)
description_sort_t	sort;
address_t		ptr;
{
	description_t	*description;

	description = NewDescription();
	description->sort = sort;

	switch (sort)
	{
	case CHEQUERED:
		description->body.chequered = (chequered_t *) ptr;
		break;

	case LAYERED:
		description->body.layered   = (layered_t *) ptr;
		break;

	case BITMAP:
		description->body.bitmap = (bitmap_t *) ptr;
		break;

	default:
		FatalError(__FILE__, __LINE__, "Description: bad sort");
	}

	return(description);
}

/* DescriptionCopy
 *
 * Make a duplicate copy of a description.
 */

description_t *
DescriptionCopy(description)
description_t	*description;
{
	description_t	*new;

	new = NewDescription();

	switch (description->sort)
	{
	case CHEQUERED:
		new->body.chequered = ChequeredCopy(description->body.chequered);
		break;

	case LAYERED:
		new->body.layered = LayeredCopy(description->body.layered);
		break;

	case BITMAP:
		new->body.bitmap = description->body.bitmap;
		break;

	default:
		FatalError(__FILE__, __LINE__, "DescriptionCopy: bad sort");
	}

	new->sort = description->sort;

	return(new);
}


/* DescriptionFree
 *
 * Free a description structure, and its sub-components.
 */

void
DescriptionFree(description)
description_t	*description;
{
	switch (description->sort)
	{
	case CHEQUERED:
		ChequeredFree(description->body.chequered);
		break;

	case LAYERED:
		LayeredFree(description->body.layered);
		break;

	case BITMAP:
		break;

	default:
		FatalError(__FILE__, __LINE__, "DescriptionFree: bad sort");
	}

	free((char *) description);
}


/* DescriptionPrint
 *
 * Print a description to a file.
 * NOT YET IMPLEMENTED
 */

void
DescriptionPrint(file, description)
FILE		*file;
description_t	*description;
{
	/* being lazy */
}


/* Chequered
 *
 * Allocate and initialise a chequered structure.
 * This sort of pattern is used to achiev the ubiquitous chessboards.
 */

chequered_t *
Chequered(x_res, y_res, z_res, surface1, surface2)
real_t		x_res, y_res, z_res;
surface_t	*surface1, *surface2;
{
	chequered_t	*chequered;

	chequered = (chequered_t *) malloc(sizeof(chequered_t));
	if (chequered == ChequeredNull)
		FatalError(__FILE__, __LINE__, "Chequered: out of memory");

	chequered->x_res = x_res;
	chequered->y_res = y_res;
	chequered->z_res = z_res;

	chequered->surface1 = surface1;
	chequered->surface2 = surface2;

	return(chequered);
}


/* ChequeredCopy
 *
 * Copy a chquered structure.
 */

chequered_t *
ChequeredCopy(chequered)
chequered_t	*chequered;
{
	return(Chequered(chequered->x_res,
			 chequered->y_res,
			 chequered->y_res,
			 chequered->surface1,
			 chequered->surface2));
}


/* ChequeredFree
 *
 * Free a chequered structure.
 */

void
ChequeredFree(chequered)
chequered_t	*chequered;
{
	free((char *) chequered);
}


/* Layered
 *
 * Allocate and initialise a layer pattern.  Layers give bands of
 * alternating surfaces along a given axis.
 */

layered_t *
Layered(res, axis, surface1, surface2)
real_t		res;
axis_t		axis;
surface_t	*surface1, *surface2;
{
	layered_t	*layered;

	layered = (layered_t *) malloc(sizeof(layered_t));
	if (layered == LayeredNull)
		FatalError(__FILE__, __LINE__, "Layered: out of memory");

	layered->res = res;
	layered->axis = axis;

	layered->surface1 = surface1;
	layered->surface2 = surface2;

	return(layered);
}


/* LayeredCopy
 *
 * Make a duplicate copy of a layered structure.
 */

layered_t *
LayeredCopy(layered)
layered_t	*layered;
{
	return(Layered(layered->res,
		       layered->axis,
		       layered->surface1,
		       layered->surface2));
}


/* LayeredFree
 *
 * Free a layered structure.
 */

void
LayeredFree(layered)
layered_t	*layered;
{
	free((char *) layered);
}
