/*
 * 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: rmclip.c,v 1.7 2005/02/19 16:22:50 wes Exp $
 * Version: $Name: v180-alpha-02 $
 * $Revision: 1.7 $
 * $Log: rmclip.c,v $
 * Revision 1.7  2005/02/19 16:22:50  wes
 * Distro sync and consolidation.
 *
 * Revision 1.6  2005/02/12 00:53:25  wes
 * Minor code reorgs (from RMSG).
 *
 * Revision 1.5  2005/01/23 17:00:22  wes
 * Copyright updated to 2005.
 *
 * Revision 1.4  2004/01/16 16:43:24  wes
 * Updated copyright line for 2004.
 *
 * Revision 1.3  2003/07/06 16:22:13  wes
 * Bug fix: rmClipPlaneSetPointNormal was always returning RM_WHACKED.
 * (Thanks to A. Yarnos for reporting this buglet).
 *
 * 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.5  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.4  2002/04/30 19:29:18  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:47  wes
 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
 *
 */

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

/*
 * ----------------------------------------------------
 * @Name rmClipPlaneNew
 @pstart
 RMclipPlane * rmClipPlaneNew (void)
 @pend

 @astart
 no arguments.
 @aend

 @dstart

 Creates a new RMclipPlane object, returning a handle to the new
 RMclipPlane object upon success, or NULL upon failure.

 The new RMclipPlane object is initialized with the following default
 values:

 1. The RMclipPlane object is disabled.

 2. Default point: (RM_DEFAULT_CLIP_PLANE_POINT) {0.,0.,0.}

 3. Default normal: (RM_DEFAULT_CLIP_PLANE_NORMAL) {0., 0., -1.}

 Applications should use rmClipPlaneDelete to release resources
 associated with the RMclipPlane object when no longer needed.

 To have the clip plane used during rendering, it needs to be
 activated (rmClipPlaneEnable), assigned whatever values you want for
 the point and normal attributes (normalized normals, please) and then
 assigned as a scene parameter to an RMnode with
 rmNodeSetSceneClipPlane.
 
 @dend
 * ----------------------------------------------------
 */
RMclipPlane *
rmClipPlaneNew (void)
{
    RMclipPlane      *cp;
    extern RMvertex3D RM_DEFAULT_CLIP_PLANE_POINT, RM_DEFAULT_CLIP_PLANE_NORMAL;

    cp = (RMclipPlane *)malloc(sizeof(RMclipPlane));
    if (cp == NULL)
    {
	rmError("rmClipPlaneNew() error: can't malloc memory for a clip plane object.");
	return(NULL);
    }
    rmClipPlaneSetPointNormal(cp, &RM_DEFAULT_CLIP_PLANE_POINT, &RM_DEFAULT_CLIP_PLANE_NORMAL);
    rmClipPlaneDisable(cp);

    return(cp);
}


/*
 * ----------------------------------------------------
 * @Name rmClipPlaneDelete
 @pstart
 RMenum rmClipPlaneDelete (RMclipPlane *toDelete)
 @pend

 @astart
 RMclipPlane *toDelete - a handle to the RMclipPlane object to be
    deleted. 
 @aend

 @dstart

 This routine releases RMclipPlane resources, the opposite of
 rmClipPlaneNew.
 
 Upon success, RM_CHILL is returned and the rmclipPlance has been
 deleted.  Otherwise, RM_WHACKED is returned.

 @dend 
 * ----------------------------------------------------
 */
RMenum
rmClipPlaneDelete (RMclipPlane *cp)
{
    if (RM_ASSERT(cp, "rmClipPlaneDelete() error: input clip plane object pointer is NULL.") == RM_WHACKED)
	return(RM_WHACKED);
    
    free((void *)cp);

    return(RM_CHILL);
}


/*
 * ----------------------------------------------------
 * @Name rmClipPlaneSetPointNormal
 @pstart
 RMenum rmClipPlaneSetPointNormal (RMclipPlane *toModify,
			           const RMvertex3D *point,
				   const RMvertex3D *normal)
 @pend

 @astart
 RMclipPlane *toModify - a handle to an RMclipPlane object that will
    be modified (input and result).

 RMvertex3D *point - a handle to a caller supplied RMvertex3D object.
    The contents of the caller's "point" value will be copied into the
    RMclipPlane's "point" attribute.

 RMvertex3D *normal - a handle to a caller supplied RMvertex3D object.
    The contents of the caller's "normal" value will be copied into
    the RMclipPlane's "normal" attribute.
 @aend

 @dstart

 A clipping plane in OpenRM is defined with two parameters, a 3D point
 and a normal.

 Use this routine to set these parameters in an RMclipPlane object.
 
 @dend
 * ----------------------------------------------------
 */
RMenum
rmClipPlaneSetPointNormal (RMclipPlane *cp,
			   const RMvertex3D *point,
			   const RMvertex3D *normal)
{
    float d;
    RMvertex3D ln, lp;

    if ((RM_ASSERT(cp, "rmClipPlaneSetPointNormal() error: the input clip plane pointer is NULL.") == RM_WHACKED) ||
	(RM_ASSERT(point, "rmClipPlaneSetPointNormal() error: the input point parameter is NULL. ") == RM_WHACKED) ||
	(RM_ASSERT(normal, "rmClipPlaneSetPointNormal() error: the input normal parameter is NULL ") == RM_WHACKED))
	return(RM_WHACKED);
    
    /* copy over vertex info for local use */
    cp->point = lp = *point;
    cp->normal = ln = *normal;
    rmVertex3DNormalize(&ln);

    /* compute a,b,c,d planar coefficients from the point-normal form.
       we assume that the normal is normalized */
    d = (ln.x * lp.x) + (ln.y * lp.y) + (ln.z * lp.z);
    d *= -1.0;

    /* store the planar coefficients */
    cp->a = ln.x;
    cp->b = ln.y;
    cp->c = ln.z;
    cp->d = d;

    return(RM_CHILL);
}


/*
 * ----------------------------------------------------
 * @Name rmClipPlaneGetPointNormal
 @pstart
 RMenum rmClipPlaneGetPointNormal (const RMclipPlane *toQuery,
			           RMvertex3D *point,
				   RMvertex3D *normal)
 @pend

 @astart
 const RMclipPlane *toQuery - a handle to an RMclipPlane object that
    will be queried (input).

 RMvertex3D *point - a handle to a caller supplied RMvertex3D object.
    The RMclipPlane's "point" attribute will be copied into this
    object (result).

 RMvertex3D *normal - a handle to a caller supplied RMvertex3D object.
    The RMclipPlane's "normal" attribute will be copied into this
    object (result). 
 @aend

 @dstart

 A clipping plane in OpenRM is defined with two parameters, a 3D point
 and a normal.

 Use this routine to obtain these parameters from an RMclipPlane
 object.
 
 @dend
 * ----------------------------------------------------
 */
RMenum
rmClipPlaneGetPointNormal (const RMclipPlane *cp,
			   RMvertex3D *point,
			   RMvertex3D *normal)
{
    if ((RM_ASSERT(cp, "rmClipPlaneGetPointNormal() error: the input clip plane pointer is NULL.") == RM_WHACKED) ||
	(RM_ASSERT(point, "rmClipPlaneGetPointNormal() error: the input point parameter is NULL. ") == RM_WHACKED) ||
	(RM_ASSERT(normal, "rmClipPlaneGetPointNormal() error: the input normal parameter is NULL ") == RM_WHACKED))
	return(RM_WHACKED);
    
    VCOPY(&(cp->point), point);
    VCOPY(&(cp->normal), normal);

    return(RM_CHILL);
}


/*
 * ----------------------------------------------------
 * @Name rmClipPlaneEnable
 @pstart
 RMenum rmClipPlaneEnable (RMclipPlane *toModify)
 @pend

 @astart
 RMclipPlane *toModify - a handle to an RMclipPlane object. This
    object will be modified by this routine.
 @aend

 @dstart

 Use this routine to "turn on" a clipping plane.

 Clipping planes are scene parameters assigned to RMnodes. Upon
 assignment, OpenRM makes a copy of the caller-supplied RMclipPlane
 object. Any application changes to the RMclipPlane object do not
 affect the copy of the RMclipPlane at the RMnode: after making
 changes, the RMclipPlane object must be reassigned to the RMnode as a
 scene parameter (see rmNodeSetSceneClipPlane()). Therefore, if the
 application maintains it's own internal array of clipping planes, any
 changes to the application RMclipPlane objects should be propogated
 to OpenRM with rmNodeSetSceneClipPlane, including deactivation.

 See also rmClipPlaneNew(). 

 @dend
 * ----------------------------------------------------
 */
RMenum
rmClipPlaneEnable (RMclipPlane *cp)
{
    if (RM_ASSERT(cp, "rmClipPlaneEnable() error: input clip plane object pointer is NULL.") == RM_WHACKED)
	return(RM_WHACKED);
    
    cp->enabled = RM_TRUE;

    return(RM_CHILL);
}


/*
 * ----------------------------------------------------
 * @Name rmClipPlaneDisable
 @pstart
 RMenum rmClipPlaneDisable (RMclipPlane *toModify)
 @pend

 @astart
 RMclipPlane *toModify - a handle to an RMclipPlane object. This
    object will be modified by this routine. 
 @aend

 @dstart

 Use this routine to "turn off" a clipping plane.

 Clipping planes are scene parameters assigned to RMnodes. Upon
 assignment, OpenRM makes a copy of the caller-supplied RMclipPlane
 object. Any application changes to the RMclipPlane object do not
 affect the copy of the RMclipPlane at the RMnode: after making
 changes, the RMclipPlane object must be reassigned to the RMnode as a
 scene parameter (see rmNodeSetSceneClipPlane()). Therefore, if the
 application maintains it's own internal array of clipping planes, any
 changes to the application RMclipPlane objects should be propogated
 to OpenRM with rmNodeSetSceneClipPlane, including deactivation.

 Applications may deactivate a clip plane by either 1. calling this
 routine to set an RMclipPlane's active attribute to "off" and then
 propogating the modified RMclipPlane to a scene graph node with
 rmNodeSetSceneClipPlane, or 2. by removing the clip plane from a
 scene graph node by calling rmNodeSetSceneClipPlane with NULL as the
 value for the RMclipPlane parameter.
 
 @dend
 * ----------------------------------------------------
 */
RMenum
rmClipPlaneDisable (RMclipPlane *cp)
{
    if (RM_ASSERT(cp, "rmClipPlaneDisable() error: input clip plane object pointer is NULL.") == RM_WHACKED)
	return(RM_WHACKED);
    
    cp->enabled = RM_FALSE;
    return(RM_CHILL);
}


/*
 * ----------------------------------------------------
 * @Name rmClipPlaneIsEnabled
 @pstart
 RMenum rmClipPlaneIsEnabled (const RMclipPlane *toQuery)
 @pend

 @astart
 const RMclipPlane *toQuery
 @aend

 @dstart

 This routine is will return to the caller RM_TRUE if the RMclipPlane
 object is "enabled", or RM_FALSE if the RMclipPlane object is
 disabled. RM_WHACKED is returned if the RMclipPlane object is NULL.

 @dend
 * ----------------------------------------------------
 */
RMenum
rmClipPlaneIsEnabled (const RMclipPlane *cp)
{
    if (RM_ASSERT(cp, "rmClipPlaneIsEnabled() error: input clip plane object pointer is NULL.") == RM_WHACKED)
	return(RM_WHACKED);
    
    return(cp->enabled);
}
/* EOF */
