/*
 * INTEL OVERLOAD
 *
 * Intel overloaded functions.
 *
 * Copyright (c) 1998 Criterion Software Ltd.
 *
 */

/****************************************************************************
 Includes
 */

#include <stdio.h>
#include <stdlib.h>

#include "rpplugin.h"
#include "rpdbgerr.h"
#include "rtintel.h"

#include "bodySSETransform.h"
#include "nodeSSETransform.h"

static const char __RWUNUSED__    rcsid[]=
    "@@(#)$Id: nodeSSETransform.c,v 1.15 2001/09/25 15:41:38 iestynb Exp $";

#if ( ((defined(__ICL)) && (400 <= __ICL)) && defined(RWSIMD) )

/****************************************************************************
 Local defines
 */

#define MESSAGE(_string)                                           \
    RwDebugSendMessage(rwDEBUGMESSAGE, "SSETransformCSL", _string)

/*****************************************************************************
 TransformNode

 Generic (non-device-specific) transform Node.

 on entry: -
 on exit : -
*/

static              RwBool
SSETransformNode(RxPipelineNodeInstance * self,
                 const RxPipelineNodeParam * __RWUNUSED__ params)
{
    RwBool              result;
    RwCamera           *camera;

    RWFUNCTION(RWSTRING("SSETransformNode"));

    camera = (RwCamera *) RWSRCGLOBAL(curCamera);
    RWASSERT(NULL != camera);

    result =
        (rwPERSPECTIVE != camera->projectionType) ?
        _rpSSETransformNodeParallel(self, camera) :
        _rpSSETransformNodePerspective(self, camera);

    RWRETURN(result);
}

#endif /* ( ((defined(__ICL)) && (400 <= __ICL)) && defined(RWSIMD) ) */

/**
 * \ingroup rtintel
 * \ref RxNodeDefinitionGetSSETransformCSL
 * returns a pointer to a node  to transform vertices into camera space
 * using SSE on Intel processors
 *
 * This takes object-space vertices and transforms them into camera space,
 * generating camera-space and screen-space vertices. It performs clipping
 * and projection in accordance with the current camera's view frustum (as
 * defined by the camera's ViewWindow, ViewOffset and Projection type - 
 * parallel or perspective). This version of the transform node uses
 * SSE on Intel processors for the matrix operations.
 *
 * The object vertices are transformed into camera space by the Obj2Cam matrix
 * which should have been set up in the mesh state cluster by an instancing
 * node (this is done by the standard Im3D in the Im3D transform pipeline and
 * the atomic and world sector instancing nodes in the atomic and world sector
 * object pipelines).
 *
 * After transformation, all generated camera vertices are tested to detect
 * if they lie outside of any or all of the current camera's clipping
 * (frustum) planes. The clip flags of the camera vertices are updated
 * accordingly. Camera-space vertices are only projected to generate valid
 * screen-space vertices if they are not clipped (screen-space vertices are
 * allocated space in their cluster and their color is filled in regardless).
 * The clip flags of all camera-space vertices are ORed together to generate a
 * ClipFlagsOr value which is stored in the mesh state cluster. Similarly a
 * ClipFlagsAnd value is generated and stored by ANDing all the clipflags
 * together. These two values are useful in determining the bulk clipping
 * properties of the packet's vertices. For example, if ClipFlagsAnd is
 * non-zero, then all of the vertices have been clipped by the same one (or
 * more) frustum plane(s). If ClipFlagsOr is zero then all of the vertices
 * are onscreen.
 *
 * \verbatim
   The node has one output, through which the transformed vertices pass.
   The input requirements of this node:
  
   RxClObjSpace3DVertices - required
   RxClCamSpace3DVertices - don't want
   RxClScrSpace2DVertices - don't want
   RxClMeshState          - required

  
   The characteristics of this node's first output:
  
   RxClObjSpace3DVertices - no change
   RxClCamSpace3DVertices - valid
   RxClScrSpace2DVertices - valid
   RxClMeshState          - valid
   \endverbatim
 *
 * \return pointer to a node to transform a vertices into camera space
 *
 * \see RxNodeDefinitionGetTransform
 */

RxNodeDefinition   *
RxNodeDefinitionGetSSETransformCSL(void)
{
#if ( ((defined(__ICL)) && (400 <= __ICL)) && defined(RWSIMD) )

    static RxClusterRef N3clofinterest[NUMCLUSTERSOFINTEREST] = { /* */
        {&RxClObjSpace3DVertices, rxCLALLOWABSENT, rxCLRESERVED},
        {&RxClCamSpace3DVertices, rxCLALLOWABSENT, rxCLRESERVED},
        {&RxClScrSpace2DVertices, rxCLALLOWABSENT, rxCLRESERVED},
        {&RxClMeshState, rxCLALLOWABSENT, rxCLRESERVED}
    };

#define NUMCLUSTERSOFINTEREST (sizeof(N3clofinterest)/sizeof(N3clofinterest[0]))

    static RxClusterValidityReq N3inputreqs[NUMCLUSTERSOFINTEREST] = { /* */
        rxCLREQ_REQUIRED,
        rxCLREQ_DONTWANT,
        rxCLREQ_DONTWANT,
        rxCLREQ_REQUIRED
    };

    static RxClusterValid N3outcl1[NUMCLUSTERSOFINTEREST] = { /* */
        rxCLVALID_VALID,
        rxCLVALID_VALID,
        rxCLVALID_VALID,
        rxCLVALID_VALID
    };

    static RxClusterValid N3outcl2[NUMCLUSTERSOFINTEREST] = { /* */
        rxCLVALID_VALID,
        rxCLVALID_VALID,
        rxCLVALID_VALID,
        rxCLVALID_VALID
    };

    static RwChar       _Output[] = RWSTRING("TransformOut");
    static RwChar       _Output2[] = RWSTRING("TransformOut2");

    static RxOutputSpec N3outputs[] = { /* */
        {_Output, N3outcl1, rxCLVALID_NOCHANGE},
        {_Output2, N3outcl2, rxCLVALID_NOCHANGE}
    };

#define NUMOUTPUTS  (sizeof(N3outputs)/sizeof(N3outputs[0]))

    static RwChar       _SSETransform_csl[] =
        RWSTRING("SSETransform.csl");
    static RxNodeDefinition nodeSSETransformCSL = { /* */
        _SSETransform_csl,
        {SSETransformNode, NULL, NULL, NULL, NULL, NULL, NULL},
        {NUMCLUSTERSOFINTEREST, N3clofinterest, N3inputreqs,
         NUMOUTPUTS, N3outputs},
        0, FALSE, 0
    };

#endif /* ( ((defined(__ICL)) && (400 <= __ICL)) && defined(RWSIMD) ) */

    RwBool              SSEEnabledCPU = FALSE;
    RxNodeDefinition   *result = (RxNodeDefinition *) NULL;

    RWAPIFUNCTION(RWSTRING("RxNodeDefinitionGetSSETransformCSL"));

#if ( ((defined(__ICL)) && (400 <= __ICL)) && defined(RWSIMD) )

    SSEEnabledCPU = RtIntelHaveSSE();

    if (SSEEnabledCPU)
    {
        result = &nodeSSETransformCSL;
    }

#endif /* ( ((defined(__ICL)) && (400 <= __ICL)) && defined(RWSIMD) ) */

    if (!SSEEnabledCPU)
    {
        RWERROR((E_RW_NOTSSEENABLEDCPU));
    }

    RWRETURN(result);
}
