/* $XConsortium: PEXlibint.h,v 1.8 92/08/26 13:05:15 mor Exp $ */

/******************************************************************************
Copyright 1987,1991 by Digital Equipment Corporation, Maynard, Massachusetts
Copyright 1992 by the Massachusetts Institute of Technology

                        All Rights Reserved

Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting documentation, and that
the name of Digital or M.I.T. not be used in advertising or publicity
pertaining to distribution of the software without specific, written prior
permission.  Digital and M.I.T. make no representations about the suitability
of this software for any purpose.  It is provided "as is" without express or
implied warranty.

DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************************/

#ifndef PEXLIBINT_H
#define PEXLIBINT_H

#include <X11/Xlibint.h>
#include <X11/Xfuncs.h>
#include "PEXproto.h"


/* -------------------------------------------------------------------------
 * Typedefs for referencing fields in requests. 
 * ------------------------------------------------------------------------- */

/*
 * Generic request header.
 */

typedef struct pexRequestHeader
{
    unsigned char       extOpcode;
    unsigned char       pexOpcode;
    unsigned short      reqLength;
} pexRequestHeader;


/*
 * OC request header.
 */

typedef struct pexOCRequestHeader
{
    unsigned char       extOpcode;
    unsigned char       pexOpcode;
    unsigned short      reqLength;
    unsigned short      fpFormat;
    unsigned short      pad;
    unsigned long       target;
    unsigned long       numCommands;
} pexOCRequestHeader;


/*
 * Element header for OC with list.
 */

typedef pexElementInfo pexOCListHeader;


/*
 * Element header for OC with list & count.
 */

typedef struct pexOCcListHeader
{
    pexElementInfo      head;
    unsigned short      length;
    unsigned short      pad;
} pexOCcListHeader;



/* -------------------------------------------------------------------------
 * Display extension data structures and macros.
 * ------------------------------------------------------------------------- */

/*
 * For each display initialized by PEXInitialize(), a record is allocated
 * which holds various information about that display.  These records are
 * maintained in a linked list.  The record for the most recently referenced
 * display is always kept at the beginning of the list (for quick access).
 */

typedef struct PEXDisplayInfo
{
    Display             *display;    /* pointer to X display structure */
    XExtCodes		*extCodes;   /* extension codes */
    PEXExtensionInfo	*extInfo;    /* extension info */
    unsigned char       extOpcode;   /* opcode for pex extension */
    unsigned short      fpFormat;    /* floating point format */
    char		fpConvert;   /* flag for floating point conversion */
    PEXEnumTypeDesc	*fpSupport;  /* float formats supported by server */
    int			fpCount;     /* number of float formats supported */
    XID       		lastResID;   /* renderer/structure ID of last OC */
    int                 lastReqType; /* request type (store/rend) of last OC */
    int			lastReqNum;  /* request number of last OC */
    struct PEXDisplayInfo *next;     /* next in list */
} PEXDisplayInfo;


/*
 * Pointer to head of list is defined externally.
 */

extern PEXDisplayInfo *PEXDisplayInfoHeader;


/*
 * Insert a new record in the beginning of the linked list.
 */

#define PEXAddDisplayInfo(_display, _info) \
\
{ \
    _info->display = _display; \
\
    _info->next = PEXDisplayInfoHeader; \
    PEXDisplayInfoHeader = _info; \
}


/*
 * Remove the record assosicated with '_display' from the linked list
 * and return a pointer to it in '_info'.
 */

#define PEXRemoveDisplayInfo(_display, _info) \
\
{ \
    PEXDisplayInfo	*prev = NULL; \
\
    _info = PEXDisplayInfoHeader; \
\
    while (_info && _info->display != _display) \
    { \
	prev = _info; \
	_info = _info->next; \
    } \
\
    if (_info) \
	if (!prev) \
	    PEXDisplayInfoHeader = _info->next; \
	else \
	    prev->next = _info->next; \
}	


/*
 * Return the info assosicated with '_display' in '_info'.
 * If the info is not the first in the list, move it to the front.
 */

#define PEXGetDisplayInfo(_display, _info) \
\
{ \
    _info = PEXDisplayInfoHeader; \
\
    if (PEXDisplayInfoHeader->display != _display) \
    { \
	PEXDisplayInfo	*prev = PEXDisplayInfoHeader; \
\
	_info = _info->next; \
	while (_info && _info->display != _display) \
	{ \
	    prev = _info; \
	    _info = _info->next; \
	} \
\
	if (_info) \
	{ \
	    prev->next = _info->next; \
	    _info->next = PEXDisplayInfoHeader; \
	    PEXDisplayInfoHeader = _info; \
	} \
    } \
}



/* -------------------------------------------------------------------------
 * Memory related macros.
 * ------------------------------------------------------------------------- */

#define PEXAllocBuf(size)          Xmalloc(size)
#define PEXFreeBuf(ptr)            Xfree(ptr)
#define PEXReallocBuf(ptr, size)   Xrealloc(ptr, size)

#define COPY_AREA(_from, _to, _size) \
    bcopy (_from, _to, _size)

#define COPY_SMALL_AREA(_from, _to, _size) \
{ \
    register char *_f = (char *) (_from), *_t = (char *) (_to); \
    register int _c = (_size); \
    while (--_c >= 0) *_t++ = *_f++; \
}

#define PAD(_size) (3 - (((_size) + 3) & 0x3))

#define PADDED_BYTES(_bytes) (_bytes + PAD (_bytes))

#define NUMWORDS(_size) (((unsigned int)((_size) + 3)) >> 2)

#define NUMBYTES(_len) (((unsigned int)(_len)) << 2)

#define LENOF(_ctype) (sizeof (_ctype) >> 2)


/* 
 * Count the number of ones in a longword.
 */

#define CountOnes(mask, countReturn) \
    countReturn = ((mask) - (((mask)>>1)&0x77777777) \
	- (((mask)>>2)&0x33333333) - (((mask)>>3)&0x11111111)); \
    countReturn = ((((countReturn)+((countReturn)>>4)) & 0x0F0F0F0F) % 255)



/* -------------------------------------------------------------------------
 * Macros for dealing with the transport buffer. 
 * ------------------------------------------------------------------------- */

/*
 * The maximum protocol request size.
 */

#define MAX_REQUEST_SIZE ((1<<16) - 1)


/*
 * Has the X transport buffer been flushed?
 */

#define XBufferFlushed(_display) \
    ((_display)->buffer == (_display)->bufptr)


/*
 * The number of bytes left in the X transport buffer.
 */

#define BytesLeftInXBuffer(_display) \
    ((_display)->bufmax - (_display)->bufptr)


/*
 * The number of words left in the X transport buffer.
 */

#define WordsLeftInXBuffer(_display) \
    (((_display)->bufmax - (_display)->bufptr) >> 2)


/*
 * Setup the OC element info header.
 */

#define STORE_ELEMENT_INFO(_reqPtr,_ocType,_ocLength) \
{ \
    ((pexElementInfo *)(_reqPtr))->elementType = (_ocType); \
    ((pexElementInfo *)(_reqPtr))->length = (_ocLength); \
}


/* 
 * PEXGetReq sets up a request to be sent to the X server.  If there isn't
 * enough room left in the X buffer, it is flushed before the new request
 * is started.
 *
 * PEXGetFPReq is similar to PEXGetReq, except that it sets up a request
 * that contains floating point values.  A return flag indicates whether
 * or not the client native floating point format has to be converted to
 * a server supported format.
 *
 * SETUP_REQ is a macro containing common code for PEXGetReq and PEXGetFPReq.
 */

#if (__STDC__ && !defined(UNIXCPP)) || (defined(__STDC__) && defined(sun)) || defined(ANSICPP)

#define SETUP_REQ(_name, _req) \
    PEXDisplayInfo *pexDisplayInfo; \
    PEXGetDisplayInfo (display, pexDisplayInfo); \
    if ((display->bufptr + sizeof (pex##_name##Req)) > display->bufmax) \
        _XFlush (display); \
    _req = (pex##_name##Req *) (display->last_req = display->bufptr); \
    _req->reqType = pexDisplayInfo->extOpcode; \
    _req->opcode = PEXRC##_name; \
    _req->length = (sizeof (pex##_name##Req)) >> 2; \
    display->bufptr += sizeof (pex##_name##Req); \
    display->request++

#else /* non-ANSI C uses empty comment instead of "##" for token concat */

#define SETUP_REQ(_name, _req) \
    PEXDisplayInfo *pexDisplayInfo; \
    PEXGetDisplayInfo (display, pexDisplayInfo); \
    if ((display->bufptr + sizeof (pex/**/_name/**/Req)) > display->bufmax) \
        _XFlush (display); \
    _req = (pex/**/_name/**/Req *) (display->last_req = display->bufptr); \
    _req->reqType = pexDisplayInfo->extOpcode; \
    _req->opcode = PEXRC/**/_name; \
    _req->length = (sizeof (pex/**/_name/**/Req)) >> 2; \
    display->bufptr += sizeof (pex/**/_name/**/Req); \
    display->request++
#endif

#define PEXGetReq(_name, _req)\
{ \
    SETUP_REQ (_name, _req); \
}

#define PEXGetFPReq(_name, _req, _fpConvert)\
{ \
    SETUP_REQ (_name, _req); \
    _req->fpFormat = pexDisplayInfo->fpFormat; \
    _fpConvert = pexDisplayInfo->fpConvert; \
}


/* 
 * PEXGetReqExtra and PEXGetFPReqExtra are the same as PEXGetReq and
 * PEXGetFPReq, except that an additional "n" bytes are allocated after
 * the request.  "n" will be padded to a word boundary.
 */

#if (__STDC__ && !defined(UNIXCPP)) || (defined(__STDC__) && defined(sun)) || defined(ANSICPP)

#define SETUP_REQ_EXTRA(_name, _n, _req) \
    PEXDisplayInfo *pexDisplayInfo; \
    PEXGetDisplayInfo (display, pexDisplayInfo); \
    if ((display->bufptr + sizeof (pex##_name##Req) + PADDED_BYTES (_n)) >\
        display->bufmax) \
        _XFlush (display); \
    _req = (pex##_name##Req *) (display->last_req = display->bufptr); \
    _req->reqType = pexDisplayInfo->extOpcode; \
    _req->opcode = PEXRC##_name; \
    _req->length = (sizeof(pex##_name##Req) + PADDED_BYTES (_n)) >> 2; \
    display->bufptr += sizeof (pex##_name##Req) + PADDED_BYTES (_n); \
    display->request++

#else /* non-ANSI C uses empty comment instead of "##" for token concat */

#define SETUP_REQ_EXTRA(_name, _n, _req) \
    PEXDisplayInfo *pexDisplayInfo; \
    PEXGetDisplayInfo (display, pexDisplayInfo); \
    if ((display->bufptr + sizeof (pex/**/_name/**/Req) + PADDED_BYTES (_n)) >\
        display->bufmax) \
        _XFlush (display); \
    _req = (pex/**/_name/**/Req *) (display->last_req = display->bufptr); \
    _req->reqType = pexDisplayInfo->extOpcode; \
    _req->opcode = PEXRC/**/_name; \
    _req->length = (sizeof(pex/**/_name/**/Req) + PADDED_BYTES (_n)) >> 2; \
    display->bufptr += sizeof (pex/**/_name/**/Req) + PADDED_BYTES (_n); \
    display->request++
#endif

#define PEXGetReqExtra(_name, _n, _req) \
{ \
    SETUP_REQ_EXTRA (_name, _n, _req); \
}

#define PEXGetFPReqExtra(_name, _n, _req, _fpConvert) \
{ \
    SETUP_REQ_EXTRA (_name, _n, _req); \
    _req->fpFormat = pexDisplayInfo->fpFormat; \
    _fpConvert = pexDisplayInfo->fpConvert; \
}


/*
 * PEXGetOCReq is similiar to PEXGetReq except that it does not update
 * display->bufptr.  This is used when writing ocs into the transport buffer.
 */

#define PEXGetOCReq(_display, _nBytes) \
{ \
    if ((_display)->bufptr + (_nBytes) > (_display)->bufmax) \
        _XFlush (_display); \
    (_display)->last_req = (_display)->bufptr; \
    (_display)->request++; \
}


/* 
 * See if XSynchronize has been called.  If so, send request right away.
 */

#define PEXSyncHandle(_display)\
    if ((_display)->synchandler) (*(_display)->synchandler) (_display)



/* -------------------------------------------------------------------------
 * Color related macros.
 * ------------------------------------------------------------------------- */

/* 
 * Return the size of the color in bytes by looking at the color type.  
 * Note that the size of an indexed color is pre-padded to a word boundary.
 */

#define GetColorSize(_type) \
    ((_type) == PEXColorTypeIndexed ? (sizeof (pexTableIndex) * 2) : \
    ((_type) == PEXColorTypeRGB8 ? sizeof (pexRgb8Color) : \
    ((_type) == PEXColorTypeRGB16 ? sizeof (pexRgb16Color) : \
	sizeof (pexRgbFloatColor))))

/*
 * Return the number of words in a color.  Note that all the PEX color
 * types are padded to end on a word boundary
 */

#define GetColorLength(_type_)\
    ((_type_) == PEXColorTypeIndexed ?  LENOF( PEXColorIndexed) :\
    ((_type_) == PEXColorTypeRGB8 ?  LENOF( PEXColorRGB8) :\
    ((_type_) == PEXColorTypeRGB16 ? LENOF( PEXColorRGB16) : \
					LENOF( PEXColorRGB) )))

/* 
 * How big, relative to the largest color specifier, is the color?
 * The users of this macro must subtract this value from the sizeof value.
 */

#define AdjustSizeFromType(_type) \
    (sizeof (pexColor) - GetColorSize (_type))


/* 
 * Initialize a color specifier.  'dst' is of type PEXColorSpecifier,
 * and 'src' is of type PEXColor.
 */

#define InitializeColorSpecifier(_dst, _src, _type)\
    (_dst).type = _type; \
    COPY_SMALL_AREA ((_src), &((_dst).value), GetColorSize (_type));


/*
 * PackColorSpecifier is similar to InitalizeColorSpecifier, except that
 * the destination is a pointer to memory, rather than a static structure.
 */

#define PackColorSpecifier(srcBuf, dstBuf, sizeColor) \
{ \
    ((PEXColorSpecifier *) (dstBuf))->type = \
        ((PEXColorSpecifier *) (srcBuf))->type; \
    sizeColor = \
        GetColorSize (((PEXColorSpecifier *) (srcBuf))->type); \
    COPY_SMALL_AREA (&(((PEXColorSpecifier *) (srcBuf))->value), \
        &(((PEXColorSpecifier *) (dstBuf))->value), sizeColor); \
}



/* -------------------------------------------------------------------------
 * Macros to compute the number of words in a facet/vertex with data.
 * ------------------------------------------------------------------------- */

/*
 * Compute the number of words in the facet data
 */

#define GetFacetDataLength(_fattribs, _lenofColor) \
    (((_fattribs & PEXGAColor) ? _lenofColor : 0) + \
    ((_fattribs & PEXGANormal) ? LENOF(pexVector3D) : 0))


/*
 * Compute the number of words in a vertex with optional colors and normals
 */

#define GetVertexWithDataLength(_vattribs, _lenofColor) \
    (LENOF (pexCoord3D) + \
    ((_vattribs & PEXGAColor) ? _lenofColor : 0) + \
    ((_vattribs & PEXGANormal) ? LENOF (pexVector3D) : 0))



/* -------------------------------------------------------------------------
 * Data structures useful for packing protocol data.
 * ------------------------------------------------------------------------- */

typedef struct
{
    unsigned long       attribute;
    unsigned char	value;
    unsigned char	reserved[3];
} PEXASFData;


typedef struct {
    short 		fp_format;
    short		reserved;
    unsigned long	renderer;
    PEXColorSpecifier	echo_color;
} PEXEchoColorData;



/* -------------------------------------------------------------------------
 * Miscellaneous.
 * ------------------------------------------------------------------------- */

/*
 * IEEE-754-32 is the most common floating point type.  Vendors who have
 * a different native floating point format should define NATIVE_FP_FORMAT
 * at compile time via the -D switch (this is done by modifying the vendors
 * config file.
 */

#ifndef NATIVE_FP_FORMAT
#define NATIVE_FP_FORMAT PEXIEEE_754_32
#endif


/*
 * INPUT and OUTPUT are defined to make looking at function arguments easier.
 */

#define INPUT  
#define OUTPUT  
#define INOUT


/*
 * Pick path cache.
 */

#define MAX_PICK_CACHE_SIZE 2048

extern PEXPickPath	*PEXPickCache;
extern unsigned int	PEXPickCacheSize;
extern int		PEXPickCacheInUse;


/*
 * _XAllocScratch is defined in Xlib.
 */

extern char *_XAllocScratch();


#endif /* PEXLIBINT_H */
