/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>


/*
 * $Header: /home/gda/dxcvs/dx/src/exec/dxmods/_unpart.c,v 1.3 1999/05/10 15:45:22 gda Exp $
 */
 
#include "unpart.h"
 
#define	GAC(_x)		DXGetArrayClass ((Array) _x)
#define	GGC(_x)		DXGetGroupClass ((Group) _x)
#define	GOC(_x)		DXGetObjectClass ((Object) _x)
 

static int
GetGroupMemberCount (Group g)
{
    int		mem	= 0;
 
    while (DXGetEnumeratedMember (g, mem, NULL))
	mem++;
    return (mem);
}
 

Error
_dxfGetFieldInformation (FieldInfo *info)
{
    Object		f	= info->obj;
    FieldInfo		local;
    FieldInfo		finfo;
    int			i, j;
    int			e, s, de, ds;
    int			items;
    int			rank;
    int			members;
    int			shape[MAXDIMS];
    Object		dep;
    char		*str;
    Error		ret	= ERROR;

    memset (&local, NULL, sizeof (local));

    local.obj   = f;

    local.class = DXGetObjectClass ((Object) f);
    if (local.class == CLASS_GROUP)
	local.class = DXGetGroupClass ((Group) f);
    if (local.class != CLASS_FIELD && local.class != CLASS_COMPOSITEFIELD)
    {
	DXSetError (ERROR_BAD_PARAMETER, "#10191", "object");
	goto cleanup;
    }

    if (local.class == CLASS_FIELD)
    {
	if (DXEmptyField ((Field) f))
	{
	    ret = OK;
	    goto cleanup;
	}

	local.data = (Array) DXGetComponentValue ((Field) f, "data");
	local.con  = (Array) DXGetComponentValue ((Field) f, "connections");
	local.pos  = (Array) DXGetComponentValue ((Field) f, "positions");
	if (local.data == NULL || local.con == NULL || local.pos == NULL)
	{
	    DXSetError (ERROR_BAD_PARAMETER, "#10240",
		      "data, positions, or connections");
	    goto cleanup;
	}

	/*
	 * Get information about what each item in the data array
	 * looks like and compute how many elements each item has.
	 */

	if (! DXGetArrayInfo (local.data, &items, &local.type, &local.cat,
			    &rank, shape))
	    goto cleanup;
	
	local.epi = 1;
	for (i = 0; i < rank; i++)
	    local.epi *= shape[i];

	/*
	 * Get the dimensioning information that describes how the
	 * data is arranged and what it depends on.
	 */

	local.dep = DEP_OTHER;
	dep = DXGetAttribute ((Object) local.data, "dep");
	if (! dep)
	{
	    DXSetError (ERROR_BAD_PARAMETER, "missing data dependency");
	    goto cleanup;
	}
	dep = DXExtractString (dep, &str);
	if (dep && str)
	{
	    if (! strcmp (str, "positions"))
		local.dep = DEP_POSITIONS;
	    else if (! strcmp (str, "connections"))
		local.dep = DEP_CONNECTIONS;
	}
	if (local.dep == DEP_OTHER)
	{
	    DXSetError (ERROR_BAD_PARAMETER, "#11250", "data");
	    goto cleanup;
	}

	/*
	 * OK, get the count in each dimension
	 */

	if (GOC (local.con) != CLASS_ARRAY ||
	    (GAC (local.con) != CLASS_MESHARRAY &&
	     GAC (local.con) != CLASS_PATHARRAY) ||
	    ! DXQueryGridConnections (local.con, &local.ndims, local.counts))
	{
	    DXSetError (ERROR_BAD_PARAMETER, "irregular connections");
	    goto cleanup;
	}
 
	/*
	 * This tells us where each partition's origin is.
	 */

	if (! DXGetMeshOffsets ((MeshArray) local.con, local.origin))
	{
	    DXSetError (ERROR_BAD_PARAMETER, "missing offsets");
	    goto cleanup;
	}

	/*
	 * Decrement the actual number of data values represented by one
	 * when dependent on connections since the data values refer to
	 * the cells NOT the vertices.  And the connections' counts always
	 * refer to the vertices.
	 */

	if (local.dep == DEP_CONNECTIONS)
	{
	    for (i = 0; i < local.ndims; i++)
		local.counts[i]--;
	}
    }
    else	/* local.class == CLASS_COMPOSITEFIELD			*/
    {
	members = GetGroupMemberCount ((Group) f);
	for (i = 0; i < members; i++)
	{
	    finfo.obj = DXGetEnumeratedMember ((Group) f, i, NULL);
	    if (! _dxfGetFieldInformation (&finfo))
		goto cleanup;
	    
	    if (i == 0)
	    {
		local = finfo;
		local.class = CLASS_COMPOSITEFIELD;
		local.members = members;
		local.data = local.con = local.pos = NULL;
		continue;
	    }

	    if (local.type  != finfo.type  ||
		local.cat   != finfo.cat   ||
		local.epi   != finfo.epi   ||
		local.ndims != finfo.ndims)
	    {
		DXSetError (ERROR_BAD_PARAMETER, "data mismatch");
		goto cleanup;
	    }

	    for (j = 0; j < local.ndims; j++)
	    {
		s  = local.origin[j];
		e  = s + local.counts[j];
		ds = s - finfo.origin[j];
		de = finfo.origin[j] + finfo.counts[j] - e;
		if (ds > 0)
		    s -= ds;
		if (de > 0)
		    e += de;
		local.origin[j] = s;
		local.counts[j] = e - s;
	    }
	}
    }

    *info = local;
    ret = OK;

cleanup:
    return (ret);
}


#define	ST_B	0x10000000
#define	ST_UB	0x20000000
#define	ST_S	0x40000000
#define	ST_US	0x80000000
#define	ST_I	0x01000000
#define	ST_UI	0x02000000
#define	ST_H	0x04000000
#define	ST_F	0x08000000
#define	ST_D	0x00100000

#define	SC_R	0x00010000
#define	SC_C	0x00020000
#define	SC_Q	0x00040000

#define	DT_B	0x00001000
#define	DT_UB	0x00002000
#define	DT_S	0x00004000
#define	DT_US	0x00008000
#define	DT_I	0x00000100
#define	DT_UI	0x00000200
#define	DT_H	0x00000400
#define	DT_F	0x00000800
#define	DT_D	0x00000010

#define	DC_R	0x00000001
#define	DC_C	0x00000002
#define	DC_Q	0x00000004


static int
SetTodoMask (FieldInfo *src, FieldInfo *dst)
{
    int		todo	= 0;

    switch (src->type)
    {
	case TYPE_BYTE:			todo |= ST_B;  break;
	case TYPE_UBYTE:		todo |= ST_UB; break;
	case TYPE_SHORT:		todo |= ST_S;  break;
	case TYPE_USHORT:		todo |= ST_US; break;
	case TYPE_INT:			todo |= ST_I;  break;
	case TYPE_UINT:			todo |= ST_UI; break;
	case TYPE_HYPER:		todo |= ST_H;  break;
	case TYPE_FLOAT:		todo |= ST_F;  break;
	case TYPE_DOUBLE:		todo |= ST_D;  break;
    }

    switch (src->cat)
    {
	case CATEGORY_REAL:		todo |= SC_R; break;
	case CATEGORY_COMPLEX:		todo |= SC_C; break;
	case CATEGORY_QUATERNION:	todo |= SC_C; break;
    }

    switch (dst->type)
    {
	case TYPE_BYTE:			todo |= DT_B;  break;
	case TYPE_UBYTE:		todo |= DT_UB; break;
	case TYPE_SHORT:		todo |= DT_S;  break;
	case TYPE_USHORT:		todo |= DT_US; break;
	case TYPE_INT:			todo |= DT_I;  break;
	case TYPE_UINT:			todo |= DT_UI; break;
	case TYPE_HYPER:		todo |= DT_H;  break;
	case TYPE_FLOAT:		todo |= DT_F;  break;
	case TYPE_DOUBLE:		todo |= DT_D;  break;
    }

    switch (dst->cat)
    {
	case CATEGORY_REAL:		todo |= DC_R; break;
	case CATEGORY_COMPLEX:		todo |= DC_C; break;
	case CATEGORY_QUATERNION:	todo |= DC_Q; break;
    }

    return (todo);
}


#define	RR_INNER(_dtype)\
{\
    *(dptr    ) = (_dtype) *(sptr    );\
}

#define	RC_INNER(_dtype)\
{\
    *(dptr    ) = (_dtype) *(sptr    );\
    *(dptr + 1) = (_dtype) 0;\
}

#define	CC_INNER(_dtype)\
{\
    *(dptr    ) = (_dtype) *(sptr    );\
    *(dptr + 1) = (_dtype) *(sptr + 1);\
}


/*
 * $$$$$ For now we are limited to, and in fact expect, 3 dimensions.
 * $$$$$$ ADD GENERAL LOOPING MECHANISM HERE $$$$$$
 */

#define	CLOOP_BODY(_stype,_dtype,_inner)\
{\
    int		i, in, di;\
    int		j, jn, dj;\
    int		k, kn, dk;\
    _stype	*sptr	= ((_stype *) sbase) + element*DXCategorySize(src->cat);\
    _dtype	*dptr;\
\
    in = src->counts[0];\
    jn = src->counts[1];\
    kn = src->counts[2];\
    di = ddelta[1] * (dst->counts[1] - src->counts[1]);\
    dj = ddelta[2] * (dst->counts[2] - src->counts[2]);\
    dk = ddelta[2];\
    dptr  = (_dtype *) dbase;\
    dptr += ddelta[0] * origin[0];\
    dptr += ddelta[1] * origin[1];\
    dptr += ddelta[2] * origin[2];\
    for (i = 0; i < in; i++)\
    {\
	for (j = 0; j < jn; j++)\
	{\
	    for (k = 0; k < kn; k++)\
	    {\
		_inner;\
		sptr += sdelta;\
		dptr += dk;\
	    }\
	    dptr += dj;\
	}\
	dptr += di;\
    }\
}

#define	ELOOP_BODY(_stype,_dtype,_inner)\
{\
    int		i, in, di;\
    int		j, jn, dj;\
    int		k, kn, dk;\
    _stype	*sptr;\
    _dtype	*dptr	= ((_dtype *) dbase) + element*DXCategorySize(dst->cat);\
\
    in = dst->counts[0];\
    jn = dst->counts[1];\
    kn = dst->counts[2];\
    di = sdelta[1] * (src->counts[1] - dst->counts[1]);\
    dj = sdelta[2] * (src->counts[2] - dst->counts[2]);\
    dk = sdelta[2];\
    sptr  = (_stype *) sbase;\
    sptr += sdelta[0] * origin[0];\
    sptr += sdelta[1] * origin[1];\
    sptr += sdelta[2] * origin[2];\
    for (i = 0; i < in; i++)\
    {\
	for (j = 0; j < jn; j++)\
	{\
	    for (k = 0; k < kn; k++)\
	    {\
		_inner;\
		dptr += ddelta;\
		sptr += dk;\
	    }\
	    sptr += dj;\
	}\
	sptr += di;\
    }\
}

#define	RR_LOOP(_stype,_dtype)	CLOOP_BODY(_stype,_dtype,RR_INNER(_dtype))
#define	RC_LOOP(_stype,_dtype)	CLOOP_BODY(_stype,_dtype,RC_INNER(_dtype))
#define	CC_LOOP(_stype,_dtype)	CLOOP_BODY(_stype,_dtype,CC_INNER(_dtype))

/*
 * $$$$$ For now the inputs "me" and "total" are not used and each
 * $$$$$ field is transfered independently.  In the future this will
 * $$$$$ be used to parallelize the collection/aggregation of single
 * $$$$$ fields and partitions where there are not enough partitions
 * $$$$$ to satisfy all of the processors.
 */

Error
_dxfCoalesceFieldElement (FieldInfo *src, FieldInfo *dst,
		      int element, int me, int total)
{
    int			d;
    int			i, in;
    Pointer		sbase;
    Pointer		dbase;
    int			sdelta;
    int			ddelta[MAXDIMS];
    int			origin[MAXDIMS];
    Error		ret	= ERROR;

    /* $$$$$$$ SEE ABOVE re: 3 dimensions $$$$$$$ */
    if (src->ndims != 3)
    {
	DXSetError (ERROR_NOT_IMPLEMENTED, "must be 3 dimensional");
	goto cleanup;
    }

    /*
     * Compute how far apart the elements in the source and destination are.
     * While we're at it compute the real offset (since the origin of the
     * space may not be at [0,0,...,0]) between the source and destination.
     */

    sdelta = DXCategorySize (src->cat) * src->epi;

    d = DXCategorySize (dst->cat);
    for (i = dst->ndims; i--; )
    {
	ddelta[i] = d;
	d *= dst->counts[i];
    }

    for (i = 0, in = src->ndims; i < in; i++)
	origin[i] = src->origin[i] - dst->origin[i];

    sbase = DXGetArrayData (src->data);
    dbase = DXGetArrayData (dst->data);

    switch (SetTodoMask (src, dst))
    {
	/* the popular cases first */
	case ST_B  | SC_R | DT_F | DC_R:	RR_LOOP (byte,float);	break;
	case ST_UB | SC_R | DT_F | DC_R:	RR_LOOP (ubyte,float);	break;
	case ST_S  | SC_R | DT_F | DC_R:	RR_LOOP (short,float);	break;
	case ST_US | SC_R | DT_F | DC_R:	RR_LOOP (ushort,float);	break;
	case ST_I  | SC_R | DT_F | DC_R:	RR_LOOP (int,float);	break;
	case ST_UI | SC_R | DT_F | DC_R:	RR_LOOP (uint,float);	break;
	case ST_F  | SC_R | DT_F | DC_R:	RR_LOOP (float,float);	break;

	case ST_B  | SC_R | DT_F | DC_C:	RC_LOOP (byte,float);	break;
	case ST_UB | SC_R | DT_F | DC_C:	RC_LOOP (ubyte,float);	break;
	case ST_S  | SC_R | DT_F | DC_C:	RC_LOOP (short,float);	break;
	case ST_US | SC_R | DT_F | DC_C:	RC_LOOP (ushort,float);	break;
	case ST_I  | SC_R | DT_F | DC_C:	RC_LOOP (int,float);	break;
	case ST_UI | SC_R | DT_F | DC_C:	RC_LOOP (uint,float);	break;
	case ST_F  | SC_R | DT_F | DC_C:	RC_LOOP (float,float);	break;

	case ST_B  | SC_C | DT_F | DC_C:	CC_LOOP (byte,float);	break;
	case ST_UB | SC_C | DT_F | DC_C:	CC_LOOP (ubyte,float);	break;
	case ST_S  | SC_C | DT_F | DC_C:	CC_LOOP (short,float);	break;
	case ST_US | SC_C | DT_F | DC_C:	CC_LOOP (ushort,float);	break;
	case ST_I  | SC_C | DT_F | DC_C:	CC_LOOP (int,float);	break;
	case ST_UI | SC_C | DT_F | DC_C:	CC_LOOP (uint,float);	break;
	case ST_F  | SC_C | DT_F | DC_C:	CC_LOOP (float,float);	break;


	/* the less likely cases */
	case ST_B  | SC_R | DT_B  | DC_R:	RR_LOOP (byte,byte); 	break;
	case ST_B  | SC_R | DT_S  | DC_R:	RR_LOOP (byte,short); 	break;
	case ST_B  | SC_R | DT_I  | DC_R:	RR_LOOP (byte,int);	break;
	case ST_B  | SC_R | DT_D  | DC_R:	RR_LOOP (byte,double);	break;

	case ST_B  | SC_R | DT_B  | DC_C:	RC_LOOP (byte,byte); 	break;
	case ST_B  | SC_R | DT_S  | DC_C:	RC_LOOP (byte,short); 	break;
	case ST_B  | SC_R | DT_I  | DC_C:	RC_LOOP (byte,int);	break;
	case ST_B  | SC_R | DT_D  | DC_C:	RC_LOOP (byte,double);	break;

	case ST_B  | SC_C | DT_B  | DC_C:	CC_LOOP (byte,byte); 	break;
	case ST_B  | SC_C | DT_S  | DC_C:	CC_LOOP (byte,short); 	break;
	case ST_B  | SC_C | DT_I  | DC_C:	CC_LOOP (byte,int);	break;
	case ST_B  | SC_C | DT_D  | DC_C:	CC_LOOP (byte,double);	break;


	case ST_UB | SC_R | DT_UB | DC_R:	RR_LOOP (ubyte,ubyte); 	break;
	case ST_UB | SC_R | DT_S  | DC_R:	RR_LOOP (ubyte,short); 	break;
	case ST_UB | SC_R | DT_US | DC_R:	RR_LOOP (ubyte,ushort);	break;
	case ST_UB | SC_R | DT_I  | DC_R:	RR_LOOP (ubyte,int);	break;
	case ST_UB | SC_R | DT_UI | DC_R:	RR_LOOP (ubyte,uint);	break;
	case ST_UB | SC_R | DT_D  | DC_R:	RR_LOOP (ubyte,double);	break;

	case ST_UB | SC_R | DT_UB | DC_C:	RC_LOOP (ubyte,ubyte); 	break;
	case ST_UB | SC_R | DT_S  | DC_C:	RC_LOOP (ubyte,short); 	break;
	case ST_UB | SC_R | DT_US | DC_C:	RC_LOOP (ubyte,ushort);	break;
	case ST_UB | SC_R | DT_I  | DC_C:	RC_LOOP (ubyte,int);	break;
	case ST_UB | SC_R | DT_UI | DC_C:	RC_LOOP (ubyte,uint);	break;
	case ST_UB | SC_R | DT_D  | DC_C:	RC_LOOP (ubyte,double);	break;

	case ST_UB | SC_C | DT_UB | DC_C:	CC_LOOP (ubyte,ubyte); 	break;
	case ST_UB | SC_C | DT_S  | DC_C:	CC_LOOP (ubyte,short); 	break;
	case ST_UB | SC_C | DT_US | DC_C:	CC_LOOP (ubyte,ushort);	break;
	case ST_UB | SC_C | DT_I  | DC_C:	CC_LOOP (ubyte,int);	break;
	case ST_UB | SC_C | DT_UI | DC_C:	CC_LOOP (ubyte,uint);	break;
	case ST_UB | SC_C | DT_D  | DC_C:	CC_LOOP (ubyte,double);	break;


	case ST_S  | SC_R | DT_S  | DC_R:	RR_LOOP (short,short); 	break;
	case ST_S  | SC_R | DT_I  | DC_R:	RR_LOOP (short,int);	break;
	case ST_S  | SC_R | DT_D  | DC_R:	RR_LOOP (short,double);	break;

	case ST_S  | SC_R | DT_S  | DC_C:	RC_LOOP (short,short); 	break;
	case ST_S  | SC_R | DT_I  | DC_C:	RC_LOOP (short,int);	break;
	case ST_S  | SC_R | DT_D  | DC_C:	RC_LOOP (short,double);	break;

	case ST_S  | SC_C | DT_S  | DC_C:	CC_LOOP (short,short); 	break;
	case ST_S  | SC_C | DT_I  | DC_C:	CC_LOOP (short,int);	break;
	case ST_S  | SC_C | DT_D  | DC_C:	CC_LOOP (short,double);	break;


	case ST_US | SC_R | DT_US | DC_R:	RR_LOOP (ushort,ushort); break;
	case ST_US | SC_R | DT_I  | DC_R:	RR_LOOP (ushort,int);	break;
	case ST_US | SC_R | DT_UI | DC_R:	RR_LOOP (ushort,uint);	break;
	case ST_US | SC_R | DT_D  | DC_R:	RR_LOOP (ushort,double);break;

	case ST_US | SC_R | DT_US | DC_C:	RC_LOOP (ushort,ushort); break;
	case ST_US | SC_R | DT_I  | DC_C:	RC_LOOP (ushort,int);	break;
	case ST_US | SC_R | DT_UI | DC_C:	RC_LOOP (ushort,uint);	break;
	case ST_US | SC_R | DT_D  | DC_C:	RC_LOOP (ushort,double);break;

	case ST_US | SC_C | DT_US | DC_C:	CC_LOOP (ushort,ushort); break;
	case ST_US | SC_C | DT_I  | DC_C:	CC_LOOP (ushort,int);	break;
	case ST_US | SC_C | DT_UI | DC_C:	CC_LOOP (ushort,uint);	break;
	case ST_US | SC_C | DT_D  | DC_C:	CC_LOOP (ushort,double);break;


	case ST_I  | SC_R | DT_I  | DC_R:	RR_LOOP (int,int);	break;
	case ST_I  | SC_R | DT_D  | DC_R:	RR_LOOP (int,double);	break;

	case ST_I  | SC_R | DT_I  | DC_C:	RC_LOOP (int,int);	break;
	case ST_I  | SC_R | DT_D  | DC_C:	RC_LOOP (int,double);	break;

	case ST_I  | SC_C | DT_I  | DC_C:	CC_LOOP (int,int);	break;
	case ST_I  | SC_C | DT_D  | DC_C:	CC_LOOP (int,double);	break;


	case ST_UI | SC_R | DT_UI | DC_R:	RR_LOOP (uint,uint);	break;
	case ST_UI | SC_R | DT_D  | DC_R:	RR_LOOP (uint,double);	break;

	case ST_UI | SC_R | DT_UI | DC_C:	RC_LOOP (uint,uint);	break;
	case ST_UI | SC_R | DT_D  | DC_C:	RC_LOOP (uint,double);	break;

	case ST_UI | SC_C | DT_UI | DC_C:	CC_LOOP (uint,uint);	break;
	case ST_UI | SC_C | DT_D  | DC_C:	CC_LOOP (uint,double);	break;


	case ST_F  | SC_R | DT_D  | DC_R:	RR_LOOP (float,double);	break;
	case ST_F  | SC_R | DT_D  | DC_C:	RC_LOOP (float,double);	break;
	case ST_F  | SC_C | DT_D  | DC_C:	CC_LOOP (float,double);	break;

	case ST_D  | SC_R | DT_D  | DC_R:	RR_LOOP (double,double);break;
	case ST_D  | SC_R | DT_D  | DC_C:	RC_LOOP (double,double);break;
	case ST_D  | SC_C | DT_D  | DC_C:	CC_LOOP (double,double);break;

	default:
	    DXSetError (ERROR_NOT_IMPLEMENTED, "unsupported conversion");
	    goto cleanup;
    }

    ret = OK;

cleanup:
    return (ret);
}

#undef	RR_LOOP
#undef	RC_LOOP
#undef	CC_LOOP


#define	RR_LOOP(_stype,_dtype)	ELOOP_BODY(_stype,_dtype,RR_INNER(_dtype))
#define	CC_LOOP(_stype,_dtype)	ELOOP_BODY(_stype,_dtype,CC_INNER(_dtype))

Error
_dxfExtractFieldElement (FieldInfo *src, FieldInfo *dst,
		      int element, int me, int total)
{
    int			d;
    int			i, in;
    Pointer		sbase;
    Pointer		dbase;
    int			ddelta;
    int			sdelta[MAXDIMS];
    int			origin[MAXDIMS];
    Error		ret	= ERROR;

    /* $$$$$$$ SEE ABOVE re: 3 dimensions $$$$$$$ */
    if (src->ndims != 3)
    {
	DXSetError (ERROR_NOT_IMPLEMENTED, "must be 3 dimensional");
	goto cleanup;
    }

    /*
     * Compute how far apart the elements in the source and destination are.
     * While we're at it compute the real offset (since the origin of the
     * space may not be at [0,0,...,0]) between the source and destination.
     */

    ddelta = DXCategorySize (dst->cat) * dst->epi;

    d = DXCategorySize (src->cat);
    for (i = src->ndims; i--; )
    {
	sdelta[i] = d;
	d *= src->counts[i];
    }

    for (i = 0, in = dst->ndims; i < in; i++)
	origin[i] = dst->origin[i] - src->origin[i];

    sbase = DXGetArrayData (src->data);
    dbase = DXGetArrayData (dst->data);

    switch (SetTodoMask (src, dst))
    {
	/* the popular cases first */
	case ST_B  | SC_R | DT_F | DC_R:	RR_LOOP (byte,float);	break;
	case ST_UB | SC_R | DT_F | DC_R:	RR_LOOP (ubyte,float);	break;
	case ST_S  | SC_R | DT_F | DC_R:	RR_LOOP (short,float);	break;
	case ST_US | SC_R | DT_F | DC_R:	RR_LOOP (ushort,float);	break;
	case ST_I  | SC_R | DT_F | DC_R:	RR_LOOP (int,float);	break;
	case ST_UI | SC_R | DT_F | DC_R:	RR_LOOP (uint,float);	break;
	case ST_F  | SC_R | DT_F | DC_R:	RR_LOOP (float,float);	break;

	case ST_B  | SC_C | DT_F | DC_C:	CC_LOOP (byte,float);	break;
	case ST_UB | SC_C | DT_F | DC_C:	CC_LOOP (ubyte,float);	break;
	case ST_S  | SC_C | DT_F | DC_C:	CC_LOOP (short,float);	break;
	case ST_US | SC_C | DT_F | DC_C:	CC_LOOP (ushort,float);	break;
	case ST_I  | SC_C | DT_F | DC_C:	CC_LOOP (int,float);	break;
	case ST_UI | SC_C | DT_F | DC_C:	CC_LOOP (uint,float);	break;
	case ST_F  | SC_C | DT_F | DC_C:	CC_LOOP (float,float);	break;


	/* the less likely cases */
	case ST_B  | SC_R | DT_B  | DC_R:	RR_LOOP (byte,byte); 	break;
	case ST_B  | SC_R | DT_S  | DC_R:	RR_LOOP (byte,short); 	break;
	case ST_B  | SC_R | DT_I  | DC_R:	RR_LOOP (byte,int);	break;
	case ST_B  | SC_R | DT_D  | DC_R:	RR_LOOP (byte,double);	break;

	case ST_B  | SC_C | DT_B  | DC_C:	CC_LOOP (byte,byte); 	break;
	case ST_B  | SC_C | DT_S  | DC_C:	CC_LOOP (byte,short); 	break;
	case ST_B  | SC_C | DT_I  | DC_C:	CC_LOOP (byte,int);	break;
	case ST_B  | SC_C | DT_D  | DC_C:	CC_LOOP (byte,double);	break;


	case ST_UB | SC_R | DT_UB | DC_R:	RR_LOOP (ubyte,ubyte); 	break;
	case ST_UB | SC_R | DT_S  | DC_R:	RR_LOOP (ubyte,short); 	break;
	case ST_UB | SC_R | DT_US | DC_R:	RR_LOOP (ubyte,ushort);	break;
	case ST_UB | SC_R | DT_I  | DC_R:	RR_LOOP (ubyte,int);	break;
	case ST_UB | SC_R | DT_UI | DC_R:	RR_LOOP (ubyte,uint);	break;
	case ST_UB | SC_R | DT_D  | DC_R:	RR_LOOP (ubyte,double);	break;


	case ST_UB | SC_C | DT_UB | DC_C:	CC_LOOP (ubyte,ubyte); 	break;
	case ST_UB | SC_C | DT_S  | DC_C:	CC_LOOP (ubyte,short); 	break;
	case ST_UB | SC_C | DT_US | DC_C:	CC_LOOP (ubyte,ushort);	break;
	case ST_UB | SC_C | DT_I  | DC_C:	CC_LOOP (ubyte,int);	break;
	case ST_UB | SC_C | DT_UI | DC_C:	CC_LOOP (ubyte,uint);	break;
	case ST_UB | SC_C | DT_D  | DC_C:	CC_LOOP (ubyte,double);	break;


	case ST_S  | SC_R | DT_S  | DC_R:	RR_LOOP (short,short); 	break;
	case ST_S  | SC_R | DT_I  | DC_R:	RR_LOOP (short,int);	break;
	case ST_S  | SC_R | DT_D  | DC_R:	RR_LOOP (short,double);	break;


	case ST_S  | SC_C | DT_S  | DC_C:	CC_LOOP (short,short); 	break;
	case ST_S  | SC_C | DT_I  | DC_C:	CC_LOOP (short,int);	break;
	case ST_S  | SC_C | DT_D  | DC_C:	CC_LOOP (short,double);	break;


	case ST_US | SC_R | DT_US | DC_R:	RR_LOOP (ushort,ushort); break;
	case ST_US | SC_R | DT_I  | DC_R:	RR_LOOP (ushort,int);	break;
	case ST_US | SC_R | DT_UI | DC_R:	RR_LOOP (ushort,uint);	break;
	case ST_US | SC_R | DT_D  | DC_R:	RR_LOOP (ushort,double);break;


	case ST_US | SC_C | DT_US | DC_C:	CC_LOOP (ushort,ushort); break;
	case ST_US | SC_C | DT_I  | DC_C:	CC_LOOP (ushort,int);	break;
	case ST_US | SC_C | DT_UI | DC_C:	CC_LOOP (ushort,uint);	break;
	case ST_US | SC_C | DT_D  | DC_C:	CC_LOOP (ushort,double);break;


	case ST_I  | SC_R | DT_I  | DC_R:	RR_LOOP (int,int);	break;
	case ST_I  | SC_R | DT_D  | DC_R:	RR_LOOP (int,double);	break;
	case ST_I  | SC_C | DT_I  | DC_C:	CC_LOOP (int,int);	break;
	case ST_I  | SC_C | DT_D  | DC_C:	CC_LOOP (int,double);	break;


	case ST_UI | SC_R | DT_UI | DC_R:	RR_LOOP (uint,uint);	break;
	case ST_UI | SC_R | DT_D  | DC_R:	RR_LOOP (uint,double);	break;
	case ST_UI | SC_C | DT_UI | DC_C:	CC_LOOP (uint,uint);	break;
	case ST_UI | SC_C | DT_D  | DC_C:	CC_LOOP (uint,double);	break;


	case ST_F  | SC_R | DT_D  | DC_R:	RR_LOOP (float,double);	break;
	case ST_F  | SC_C | DT_D  | DC_C:	CC_LOOP (float,double);	break;

	case ST_D  | SC_R | DT_D  | DC_R:	RR_LOOP (double,double);break;
	case ST_D  | SC_C | DT_D  | DC_C:	CC_LOOP (double,double);break;

	default:
	    DXSetError (ERROR_NOT_IMPLEMENTED, "unsupported conversion");
	    goto cleanup;
    }

    ret = OK;

cleanup:
    return (ret);
}
