/*
 * Copyright (C) 1997-2009, R3vis Corporation.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
 *
 * Original Contributor:
 *   Wes Bethel, R3vis Corporation, Marin County, California
 *   http://www.r3vis.com/
 * Additional Contributor(s):
 *
 * The OpenRM project is located at http://openrm.sourceforge.net/.
 */
/*
 * $Id: rmmalloc.c,v 1.7 2008/11/23 15:12:06 wes Exp $
 * Version: $Name: v180-alpha-02 $
 * $Revision: 1.7 $
 * $Log: rmmalloc.c,v $
 * Revision 1.7  2008/11/23 15:12:06  wes
 * Use size_t rather than int for input parameter to rmVertex*New() and
 * rmColor*New() routines.
 *
 * Revision 1.6  2005/02/27 19:34:04  wes
 * Added support for application supplied texture object IDs and display lists.
 *
 * Revision 1.5  2005/02/19 16:22:50  wes
 * Distro sync and consolidation.
 *
 * Revision 1.4  2005/01/23 17:04:03  wes
 * Copyright update to 2005.
 *
 * Revision 1.3  2004/01/16 16:46:09  wes
 * Updated copyright line for 2004.
 *
 * Revision 1.2  2003/02/02 02:07:15  wes
 * Updated copyright to 2003.
 *
 * Revision 1.1.1.1  2003/01/28 02:15:23  wes
 * Manual rebuild of rm150 repository.
 *
 * Revision 1.6  2003/01/16 22:21:17  wes
 * Updated all source files to reflect new organization of header files:
 * all header files formerly located in include/rmaux, include/rmi, include/rmv
 * are now located in include/rm.
 *
 * Revision 1.5  2002/09/17 14:20:25  wes
 * Sanitized some comments.
 *
 * Revision 1.4  2002/04/30 19:32:22  wes
 * Updated copyright dates.
 *
 * Revision 1.3  2001/03/31 17:12:38  wes
 * v1.4.0-alpha-2 checkin.
 *
 * Revision 1.2  2000/04/20 16:29:47  wes
 * Documentation additions/enhancements, some code rearragement.
 *
 * Revision 1.1.1.1  2000/02/28 21:29:40  wes
 * OpenRM 1.2 Checkin
 *
 * Revision 1.1.1.1  2000/02/28 17:18:48  wes
 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
 *
 */

#include <rm/rm.h>
#include "rmprivat.h"

/*
 * ----------------------------------------------------
 * @Name rmFloatNew
 @pstart
 float * rmFloatNew (int n)
 @pend

 @astart
 int n - number of floats to create (input).
 @aend

 @dstart

 Return a handle to the requested number of floats.

 @dend
 * ----------------------------------------------------
 */
float * 
rmFloatNew (int n)
{
    return((float *)(malloc(sizeof(float) * n)));
}


/*
 * ----------------------------------------------------
 * @Name rmFloatDelete
 @pstart
 void rmFloatDelete (float *t)
 @pend

 @astart
 float *t - a handle to float(s) to delete (modified).
 @aend

 @dstart

 Free the float resources pointed to by t.

 @dend
 * ----------------------------------------------------
 */
void
rmFloatDelete (float *t)
{
    free((void *)t);
}


/*
 * ----------------------------------------------------
 * @Name rmVertex2DNew
 @pstart
 RMvertex2D * rmVertex2DNew (size_t n)
 @pend

 @astart
 size_t n - number of RMvertex2D objects to create (input).
 @aend

 @dstart

 Return a handle to the requested number of RMvertex2D.

 @dend
 * ----------------------------------------------------
 */
RMvertex2D *
rmVertex2DNew (size_t n)
{
    RMvertex2D *v;

    v = (RMvertex2D *)malloc(sizeof(RMvertex2D) * n);

    return(v);
}


/*
 * ----------------------------------------------------
 * @Name rmVertex2DDelete
 @pstart
 void rmVertex2DDelete (RMvertex2D *v)
 @pend

 @astart
 RMvertex2D *v - a handle to RMvertex2D object(s) to delete
    (modified). 
 @aend

 @dstart

 Free the RMvertex2D resources pointed to by v.  It is assumed that v
 points to a valid RMvertex2D previously created with rmVertex2DNew.

 @dend
 * ----------------------------------------------------
 */
void
rmVertex2DDelete (RMvertex2D *v)
{
    if (RM_ASSERT(v, "rmVertex2DDelete() error: input RMvertex2D pointer is NULL.") == RM_WHACKED)
	return;

    free((void *)v);
}


/*
 * ----------------------------------------------------
 * @Name rmVertex3DNew
 @pstart
 RMvertex3D * rmVertex3DNew (size_t n)
 @pend

 @astart
 size_t n - number of RMvertex3D objects to create (input).
 @aend

 @dstart

 Return a handle to the requested number of RMvertex3D.

 @dend
 * ----------------------------------------------------
 */
RMvertex3D *
rmVertex3DNew (size_t n)
{
    RMvertex3D *v;
    v = (RMvertex3D *)malloc(sizeof(RMvertex3D) * n);

    return(v);
}


/*
 * ----------------------------------------------------
 * @Name rmVertex3DDelete
 @pstart
 void rmVertex3DDelete (RMvertex3D *v)
 @pend

 @astart

 RMvertex3D *v - a handle to RMvertex3D object(s) to delete
    (modified). 
 @aend

 @dstart

 Free the RMvertex3D resources pointed to by v.  It is assumed that v
 points to a valid RMvertex3D previously created with rmVertex3DNew.

 @dend
 * ----------------------------------------------------
 */
void
rmVertex3DDelete (RMvertex3D *v)
{
    if (RM_ASSERT(v, "rmVertex3DDelete() error: input RMvertex3D pointer is NULL.") == RM_WHACKED)
	return;
    
    free(v);
}

/*
 * placeholder docs rmColor3DNew, which is really a macro for rmVertex3DNew
 * ----------------------------------------------------
 * @Name rmColor3DNew
 @pstart
 RMcolor3D * rmColor3DNew (size_t n)
 @pend

 @astart
 size_t n - number of RMcolor3D objects to create (input).
 @aend

 @dstart

 Returns a handle to a 1D array of RMcolor3D's that is "n" in length.

 @dend
 * ----------------------------------------------------
 */

/*
 * ----------------------------------------------------
 * @Name rmColor3DDelete
 @pstart
 void rmColor3DDelete (RMcolor4D *c)
 @pend

 @astart
 RMcolor3D *c - a handle to RMcolor3D object(s) to delete (modified).
 @aend

 @dstart

 Free the RMcolor3D resources pointed to by c.  It is assumed
 that c points to a valid RMcolor3D previously created with
 rmColor3DNew().

 @dend
 * ----------------------------------------------------
 */
/*
 * ----------------------------------------------------
 * @Name rmColor4DNew
 @pstart
 RMcolor4D * rmColor4DNew (size_t n)
 @pend

 @astart
 size_t n - number of RMcolor4D objects to create (input).
 @aend

 @dstart

 Returns a handle to a 1D array of RMcolor4D's that is "n" in length.

 @dend
 * ----------------------------------------------------
 */
RMcolor4D *
rmColor4DNew (size_t n)
{
    return(malloc(sizeof(RMcolor4D) * n));
}


/*
 * ----------------------------------------------------
 * @Name rmColor4DDelete
 @pstart
 void rmColor4DDelete (RMcolor4D *c)
 @pend

 @astart
 RMcolor4D *c - a handle to RMcolor4D object(s) to delete (modified).
 @aend

 @dstart

 Free the RMcolor4D resources pointed to by c.  It is assumed
 that c points to a valid RMcolor4D previously created with
 rmColor4DNew().

 @dend
 * ----------------------------------------------------
 */
void
rmColor4DDelete (RMcolor4D *c)
{
    if (c != NULL)
	free((void *)c);
}


/*
 * ----------------------------------------------------
 * @Name rmInternalMarker2DNew
 @pstart
 RMinternalMarker2D * rmInternalMarker2DNew (int nverts,
		                             int begin_flag,
		                             RMvertex2D *dverts)
 @pend

 @astart
 int nverts - number of vertices in the RMinternalMarker2D list.

 int begin_flag - ?

 RMvertex2D *dverts - vertex data.
 @aend

 @dstart

 This routine may be deprecated. Need to add checks to see if this is
 actually being used by any contemporary applications.

 Create a new RMinternalMarker2D from the given parameters and return
 a handle to the caller.

 @dend
 * ----------------------------------------------------
 */
RMinternalMarker2D *
rmInternalMarker2DNew (int nverts,
		       int begin_flag,
		       RMvertex2D *dverts)
{
    RMinternalMarker2D *t;

    t = (RMinternalMarker2D *)malloc(sizeof(RMinternalMarker2D));
    memset(t, 0, sizeof(RMinternalMarker2D));
    
    t->vlist = rmVertex2DNew(nverts);
    memcpy(t->vlist, dverts, sizeof(RMvertex2D)*nverts);
    rmInternalMarker2DSetNpts(t, nverts);
    rmInternalMarker2DSetBFlag(t, begin_flag);

    return(t);
}


/*
 * ----------------------------------------------------
 * @Name rmInternalMarker2DDelete
 @pstart
 void rmInternalMarker2DDelete (RMinternalMarker2D *t)
 @pend

 @astart
 RMinternalMarker2D *t - a handle to RMinternalMarker2D object to
    delete (modified). 
 @aend

 @dstart

 Free the RMinternalMarker2D resources pointed to by t.  It is assumed
 that t points to a valid RMinternalMarker2D previously created with
 rmInternalMarker2DNew().

 @dend
 * ----------------------------------------------------
 */
void
rmInternalMarker2DDelete (RMinternalMarker2D *t)
{
    free(t->vlist);
    free(t);
}


/*
 * ----------------------------------------------------
 * @Name rmMalloc2DByteBuffer
 @pstart
 unsigned char ** rmMalloc2DByteBuffer (int width,
                                        int height)
 @pend

 @astart
 int width - buffer width in bytes (input).

 int height - buffer height in bytes (input).
 @aend

 @dstart
 
 Creates a 2D byte buffer of the requested dimensions and returns a
 handle to the caller.  The resulting buffer is row-major order, so
 indexing it as an array of unsigned char means that the first index
 is the row (height) and the second index is the column (width).

 @dend
 * ----------------------------------------------------
 */
unsigned char **
rmMalloc2DByteBuffer (int width,
		      int height)
{
    int             i;
    unsigned char **c2;
    unsigned char  *c;

    c = (unsigned char *)malloc(sizeof(unsigned char) * width * height);
    c2 = (unsigned char **)malloc(sizeof(unsigned char *) * height);

    for (i = 0; i < height; i++)
	c2[i] = c + (i * width);

    memset(c, 0, sizeof(unsigned char) * width * height);

    return(c2);
}


/*
 * ----------------------------------------------------
 * @Name rmFree2DByteBuffer
 @pstart
 void rmFree2DByteBuffer (unsigned char **c)
 @pend

 @astart
 unsigned char **c - a handle to a 2D byte buffer (modified).
 @aend

 @dstart

 Free the 2D byte buffer resources pointed to by c.  It is assumed
 that c points to a valid 2D byte buffer previously created with
 rmMalloc2DByteBuffer().

 @dend
 * ----------------------------------------------------
 */
void
rmFree2DByteBuffer (unsigned char **c)
{
    free(c[0]);
    free(c);
}


/*
 * ----------------------------------------------------
 * @Name rmMalloc2DFloatBuffer
 @pstart
 float ** rmMalloc2DFloatBuffer (int width,
		                 int height)
 @pend

 @astart
 int width -  buffer width in floats (input).

 int height -  buffer height in floats (input).
 @aend

 @dstart
 
 Creates a 2D float buffer of the requested dimensions and returns a
 handle to the caller.  The resulting buffer is row-major order, so
 indexing it as an array of unsigned char means that the first index
 is the row (height) and the second index is the column (width).

 @dend
 * ----------------------------------------------------
 */
float **
rmMalloc2DFloatBuffer (int width,
		       int height)
{
    int     i;
    float **c2;
    float  *c;

    c = (float *)malloc(sizeof(float) * width * height);
    c2 = (float **)malloc(sizeof(float *) * height);

    for (i = 0; i < height; i++)
	c2[i] = c + (i * width);

    return(c2);
}


/*
 * ----------------------------------------------------
 * @Name rmFree2DFloatBuffer
 @pstart
 void rmFree2DFloatBuffer (float **c)
 @pend

 @astart
 float **c - a handle to a 2D byte buffer (modified).
 @aend

 @dstart

 Free the 2D float buffer resources pointed to by c.  It is assumed
 that c points to a valid 2D float buffer previously created with
 rmMalloc2DFloatBuffer().

 @dend
 * ----------------------------------------------------
 */
void
rmFree2DFloatBuffer (float **c)
{
    free(c[0]);
    free(c);
}


/*
 * ----------------------------------------------------
 * @Name rmMalloc3DByteBuffer
 @pstart
 unsigned char *** rmMalloc3DByteBuffer (int width,
		                         int height,
		                         int depth)
 @pend

 @astart
 int width - buffer width in bytes (input).

 int height - buffer height in bytes (input).

 int depth - buffer depth in bytes (input).
 @aend

 @dstart
 
 Creates a 3D byte buffer of the requested dimensions and returns a
 handle to the caller.  The resulting buffer is row-major order, so
 indexing it as an array of unsigned char means that the first index
 is the row (height) and the second index is the column (width).

 @dend
 * ----------------------------------------------------
 */
unsigned char ***
rmMalloc3DByteBuffer (int width,
		      int height,
		      int depth)
{
    int              i;
    unsigned char ***c3;
    unsigned char  **c2;
    unsigned char   *c;

    c = (unsigned char *)malloc(sizeof(unsigned char) * width * height * depth);
    c2 = (unsigned char **)malloc(sizeof(unsigned char *) * height * depth);
    c3 = (unsigned char ***)malloc(sizeof(unsigned char **) * depth);

    for (i = 0; i < (height * depth); i++)
	c2[i] = c + (i * width);

    for (i = 0; i < depth; i++)
	c3[i] = c2 + (depth * i);

    memset(c, 0, sizeof(unsigned char) * width * height * depth);

    return(c3);
}


/*
 * ----------------------------------------------------
 * @Name rmFree3DByteBuffer
 @pstart
 void rmFree3DByteBuffer (unsigned char ***c)
 @pend

 @astart
 unsigned char ***c - a handle to a 3D byte buffer (modified).
 @aend

 @dstart

 Free the 3D byte buffer resources pointed to by c.  It is assumed
 that c points to a valid 3D byte buffer previously created with
 rmMalloc3DByteBuffer().

 @dend
 * ----------------------------------------------------
 */
void
rmFree3DByteBuffer (unsigned char ***c)
{
    free(c[0][0]);
    free(c[0]);
    free(c);
}


/*
 * ----------------------------------------------------
 * @Name rmMalloc3DFloatBuffer
 @pstart
 float *** rmMalloc3DFloatBuffer (int width,
		                  int height,
		                  int depth)
 @pend

 @astart
 int width - buffer width in floats (input).

 int height - buffer height in floats (input).

 int depth - buffer depth in floats (input).
 @aend

 @dstart
 
 Creates a 3D float buffer of the requested dimensions and returns a
 handle to the caller.  The resulting buffer is row-major order, so
 indexing it as an array of unsigned char means that the first index
 is the row (height) and the second index is the column (width).

 @dend
 * ----------------------------------------------------
 */
float ***
rmMalloc3DFloatBuffer (int width,
		       int height,
		       int depth)
{
    int      i;
    float ***c3;
    float  **c2;
    float   *c;

    c = (float *)malloc(sizeof(float) * width * height * depth);
    c2 = (float **)malloc(sizeof(float *) * height * depth);
    c3 = (float ***)malloc(sizeof(float **) * depth);

    for (i = 0; i < (height * depth); i++)
	c2[i] = c + (i * width);

    for (i = 0; i < depth; i++)
	c3[i] = c2 + (depth * i);

    memset(c, 0, sizeof(float) * width * height * depth);

    return(c3);
}


/*
 * ----------------------------------------------------
 * @Name rmFree3DFloatBuffer
 @pstart
 void rmFree3DFloatBuffer (float ***c)
 @pend

 @astart
 float ***c - a handle to a 3D float buffer (modified).
 @aend

 @dstart

 Free the 3D float buffer resources pointed to by c.  It is assumed
 that c points to a valid 3D float buffer previously created with
 rmMalloc3DFloatBuffer().

 @dend
 * ----------------------------------------------------
 */
void
rmFree3DFloatBuffer (float ***c)
{
    free(c[0][0]);
    free(c[0]);
    free(c);
}


/* PRIVATE 
 *
 * private_rmAssert is called by the macro RM_ASSERT()
 */
int
private_rmAssert (const void *a,
		  const char *s)
{
    if (a == NULL)
    {
	rmError(s);
	return(RM_WHACKED);
    }
    return(RM_CHILL);
}

void *
private_rmMemDup(void *src, 
		 int sizeOfInput)
{
    void *dst;
    dst = (void *)malloc(sizeOfInput);

    if (dst == NULL)
    {
	char buf[256];
	sprintf(buf, "private_rmMemDup() error - unable to duplicate %d bytes of memory.", sizeOfInput);
	return NULL;
    }

    memcpy(dst, src, sizeOfInput);
    return dst;
}
/* EOF */
