/* Computer Graphics
 *
 * Filename ........ polys.c
 * Description ..... Functions to manage lists of polygons
 * Date ............ 19.08.2008
 * Created by ...... Jurgen Sturm
 * Cleaned up by ... Paul Melis
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "polys.h"

/* Create a list of polys, and reserve space for `n' polys */

polys*
CreatePolylist(int n)
{
    polys *l;

    l = (polys*) malloc(sizeof(polys));

    if (l == NULL)
    {
        printf("CreatePolylist(): could not allocate memory (l): %s\n",
           strerror(errno));
        exit(-1);
    }

    if (n > 0)
    {
        l->items = (poly*) malloc(n * sizeof(poly));

        if (l->items == NULL)
        {
            printf("CreatePolylist(): could not allocate memory (data): %s\n",
                strerror(errno));
            exit(-1);
        }

        l->capacity = n;
        l->length = 0;
    }
    else
    {
        l->capacity = 0;
        l->length = 0;
        l->items = NULL;
    }

    return l;
}

/* Free the memory used by the given poly list */

void
DestroyPolylist(polys *list)
{
    if (list == NULL)
        return;

    list->capacity = 0;
    list->length = 0;
    free(list->items);

    list = NULL;
}

/* Enlarge the capacity of the given polylist by "delta" items *
 * exit()'s if not enough memory is available.
 * Returns 0 if poly* is NULL, 1 otherwise */
int
GrowPolylist(polys *list, int delta)
{
    poly    *newdata;

    if (list == NULL)
        return 0;

    newdata = (poly*) realloc(list->items, (list->capacity + delta)*sizeof(poly));

    if (newdata == NULL)
    {
        printf("GrowPolylist(): could not allocate memory: %s\n",
            strerror(errno));
        exit(-1);
    }

    list->capacity += delta;
    list->items = newdata;

    return 1;
}


/* Decrease the capacity of the given polylist by "delta" items.
 * exit()'s if no memory available, returns 0 if poly* is NULL, 1 otherwise.
 * Decreasing the data segment can, and will, destroy polygons if the new
 * segment cannot contain all current data.
 * The data segment cannot be reduced to a size less than 0 (size is clamped
 * to zero).
 * The new data segment will be a NULL pointer if the new size is 0. */
int
ShrinkPolylist(polys *list, int delta)
{
    int     n;
    poly    *newdata;

    if (list == NULL)
        return 0;

    n = list->capacity - delta;
    if (n < 1)
    {
        free(list->items);
        list->items = NULL;
        list->capacity = 0;
        list->length = 0;

        return 1;
    }

    newdata = (poly*)realloc(list->items, (list->capacity + delta)*sizeof(poly));

    if (newdata == NULL)
    {
        printf("ShrinkPolylist(): could not allocate memory: %s\n",
            strerror(errno));
        exit(-1);
    }

    list->capacity -= delta;
    list->items = newdata;

    /* update list->length if neccesary */
    if (list->length > list->capacity)
        list->length = list->capacity;

    return 1;
}


/* Add polygon p to the list.
 * Note: the list will be enlarged if needed to accomodate p */
void
AddPolyToPolylist(polys *list, poly p)
{
    int     i;

    if (list == NULL)
        return;

    for (i = 0; i < p.points; i++)
    {
        p.normal[i].x = 0;
        p.normal[i].y = 0;
        p.normal[i].z = 0;
    }

    /* polylist is full, so first add some space */
    if (list->length == list->capacity)
    {
        /* grow arbitrary amount */
        if (GrowPolylist(list, 8) != 1)
        {
            printf("AddPolyToList(): failed");
            exit(-1);
        }
    }

    list->items[list->length] = p;
    list->length++;
}

/* Make a copy of the given list */
polys*
CopyPolylist(polys* list)
{
    int     i;
    polys   *copy;

    if (list == NULL)
        return NULL;

    copy = CreatePolylist(list->capacity);

    /* not the most efficient, but certainly easiest & least error-prone */
    for (i = 0; i < list->length; i++)
        AddPolyToPolylist(copy, list->items[i]);

    return copy;
}


