470 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			470 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Copyright © 2004 Eric Anholt
 | 
						|
 *
 | 
						|
 * 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 Eric Anholt not be used in
 | 
						|
 * advertising or publicity pertaining to distribution of the software without
 | 
						|
 * specific, written prior permission.  Eric Anholt makes no
 | 
						|
 * representations about the suitability of this software for any purpose.  It
 | 
						|
 * is provided "as is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
						|
 * EVENT SHALL ERIC ANHOLT 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.
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include "gcstruct.h"
 | 
						|
#include "windowstr.h"
 | 
						|
#include "cw.h"
 | 
						|
 | 
						|
#define cwPsDecl(pScreen)	\
 | 
						|
    PictureScreenPtr	ps = GetPictureScreen (pScreen);	\
 | 
						|
    cwScreenPtr		pCwScreen = getCwScreen (pScreen)
 | 
						|
 | 
						|
#define cwPicturePrivate					\
 | 
						|
    cwPicturePtr    pPicturePrivate = getCwPicture(pPicture)
 | 
						|
 | 
						|
#define cwSrcPictureDecl							\
 | 
						|
    int		    src_picture_x_off, src_picture_y_off;			\
 | 
						|
    PicturePtr	    pBackingSrcPicture = cwGetBackingPicture(pSrcPicture,	\
 | 
						|
							     &src_picture_x_off,\
 | 
						|
							     &src_picture_y_off)
 | 
						|
 | 
						|
#define cwDstPictureDecl							\
 | 
						|
    int		    dst_picture_x_off, dst_picture_y_off;			\
 | 
						|
    PicturePtr	    pBackingDstPicture = cwGetBackingPicture(pDstPicture,	\
 | 
						|
							     &dst_picture_x_off,\
 | 
						|
							     &dst_picture_y_off)
 | 
						|
 | 
						|
#define cwMskPictureDecl							\
 | 
						|
    int		    msk_picture_x_off = 0, msk_picture_y_off = 0;		\
 | 
						|
    PicturePtr	    pBackingMskPicture = (!pMskPicture ? 0 :	    		\
 | 
						|
					  cwGetBackingPicture(pMskPicture,	\
 | 
						|
							      &msk_picture_x_off,\
 | 
						|
							      &msk_picture_y_off))
 | 
						|
 | 
						|
#define cwPsUnwrap(elt) {	\
 | 
						|
    ps->elt = pCwScreen->elt;	\
 | 
						|
}
 | 
						|
 | 
						|
#define cwPsWrap(elt,func) {	\
 | 
						|
    pCwScreen->elt = ps->elt;	\
 | 
						|
    ps->elt = func;		\
 | 
						|
}
 | 
						|
 | 
						|
static cwPicturePtr
 | 
						|
cwCreatePicturePrivate (PicturePtr pPicture)
 | 
						|
{
 | 
						|
    WindowPtr	    pWindow = (WindowPtr) pPicture->pDrawable;
 | 
						|
    PixmapPtr	    pPixmap = getCwPixmap (pWindow);
 | 
						|
    int		    error;
 | 
						|
    cwPicturePtr    pPicturePrivate;
 | 
						|
 | 
						|
    pPicturePrivate = malloc(sizeof (cwPictureRec));
 | 
						|
    if (!pPicturePrivate)
 | 
						|
	return NULL;
 | 
						|
    
 | 
						|
    pPicturePrivate->pBackingPicture = CreatePicture (0, &pPixmap->drawable, 
 | 
						|
						      pPicture->pFormat,
 | 
						|
						      0, 0, serverClient,
 | 
						|
						      &error);
 | 
						|
    if (!pPicturePrivate->pBackingPicture)
 | 
						|
    {
 | 
						|
	free(pPicturePrivate);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * Ensure that this serial number does not match the window's
 | 
						|
     */
 | 
						|
    pPicturePrivate->serialNumber = pPixmap->drawable.serialNumber;
 | 
						|
    pPicturePrivate->stateChanges = (1 << (CPLastBit + 1)) - 1;
 | 
						|
    
 | 
						|
    setCwPicture(pPicture, pPicturePrivate);
 | 
						|
 | 
						|
    return pPicturePrivate;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cwDestroyPicturePrivate (PicturePtr pPicture)
 | 
						|
{
 | 
						|
    cwPicturePrivate;
 | 
						|
 | 
						|
    if (pPicturePrivate)
 | 
						|
    {
 | 
						|
	if (pPicturePrivate->pBackingPicture)
 | 
						|
	    FreePicture (pPicturePrivate->pBackingPicture, 0);
 | 
						|
	free(pPicturePrivate);
 | 
						|
	setCwPicture(pPicture, NULL);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static PicturePtr
 | 
						|
cwGetBackingPicture (PicturePtr pPicture, int *x_off, int *y_off)
 | 
						|
{
 | 
						|
    cwPicturePrivate;
 | 
						|
 | 
						|
    if (pPicturePrivate)
 | 
						|
    {
 | 
						|
	DrawablePtr pDrawable = pPicture->pDrawable;
 | 
						|
	WindowPtr   pWindow = (WindowPtr) pDrawable;
 | 
						|
	PixmapPtr   pPixmap = getCwPixmap (pWindow);
 | 
						|
 | 
						|
	*x_off = pDrawable->x - pPixmap->screen_x;
 | 
						|
	*y_off = pDrawable->y - pPixmap->screen_y;
 | 
						|
 | 
						|
	return pPicturePrivate->pBackingPicture;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	*x_off = *y_off = 0;
 | 
						|
	return pPicture;
 | 
						|
    }
 | 
						|
}
 | 
						|
    
 | 
						|
static void
 | 
						|
cwDestroyPicture (PicturePtr pPicture)
 | 
						|
{
 | 
						|
    ScreenPtr		pScreen = pPicture->pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    
 | 
						|
    cwPsUnwrap(DestroyPicture);
 | 
						|
    cwDestroyPicturePrivate (pPicture);
 | 
						|
    (*ps->DestroyPicture) (pPicture);
 | 
						|
    cwPsWrap(DestroyPicture, cwDestroyPicture);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cwChangePicture (PicturePtr pPicture, Mask mask)
 | 
						|
{
 | 
						|
    ScreenPtr		pScreen = pPicture->pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    cwPicturePtr	pPicturePrivate = getCwPicture(pPicture);
 | 
						|
    
 | 
						|
    cwPsUnwrap(ChangePicture);
 | 
						|
    (*ps->ChangePicture) (pPicture, mask);
 | 
						|
    if (pPicturePrivate)
 | 
						|
	pPicturePrivate->stateChanges |= mask;
 | 
						|
    cwPsWrap(ChangePicture, cwChangePicture);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
cwValidatePicture (PicturePtr pPicture,
 | 
						|
		   Mask       mask)
 | 
						|
{
 | 
						|
    DrawablePtr		pDrawable = pPicture->pDrawable;
 | 
						|
    ScreenPtr		pScreen = pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    cwPicturePrivate;
 | 
						|
    
 | 
						|
    cwPsUnwrap(ValidatePicture);
 | 
						|
 | 
						|
    /*
 | 
						|
     * Must call ValidatePicture to ensure pPicture->pCompositeClip is valid
 | 
						|
     */
 | 
						|
    (*ps->ValidatePicture) (pPicture, mask);
 | 
						|
    
 | 
						|
    if (!cwDrawableIsRedirWindow (pDrawable))
 | 
						|
    {
 | 
						|
	if (pPicturePrivate)
 | 
						|
	    cwDestroyPicturePrivate (pPicture);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	PicturePtr  pBackingPicture;
 | 
						|
	DrawablePtr pBackingDrawable;
 | 
						|
	int	    x_off, y_off;
 | 
						|
	
 | 
						|
	pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
 | 
						|
 | 
						|
	if (pPicturePrivate && 
 | 
						|
	    pPicturePrivate->pBackingPicture->pDrawable != pBackingDrawable)
 | 
						|
	{
 | 
						|
	    cwDestroyPicturePrivate (pPicture);
 | 
						|
	    pPicturePrivate = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!pPicturePrivate)
 | 
						|
	{
 | 
						|
	    pPicturePrivate = cwCreatePicturePrivate (pPicture);
 | 
						|
	    if (!pPicturePrivate)
 | 
						|
	    {
 | 
						|
		cwPsWrap(ValidatePicture, cwValidatePicture);
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	pBackingPicture = pPicturePrivate->pBackingPicture;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Always copy transform and filters because there's no
 | 
						|
	 * indication of when they've changed
 | 
						|
	 */
 | 
						|
	SetPictureTransform(pBackingPicture, pPicture->transform);
 | 
						|
	
 | 
						|
	if (pBackingPicture->filter != pPicture->filter ||
 | 
						|
	    pPicture->filter_nparams > 0)
 | 
						|
	{
 | 
						|
	    char    *filter = PictureGetFilterName (pPicture->filter);
 | 
						|
	    
 | 
						|
	    SetPictureFilter(pBackingPicture,
 | 
						|
			     filter, strlen (filter),
 | 
						|
			     pPicture->filter_params,
 | 
						|
			     pPicture->filter_nparams);
 | 
						|
	}
 | 
						|
 | 
						|
	pPicturePrivate->stateChanges |= mask;
 | 
						|
 | 
						|
	if (pPicturePrivate->serialNumber != pDrawable->serialNumber ||
 | 
						|
	    (pPicturePrivate->stateChanges & (CPClipXOrigin|CPClipYOrigin|CPClipMask)))
 | 
						|
	{
 | 
						|
	    SetPictureClipRegion (pBackingPicture, 
 | 
						|
				  x_off - pDrawable->x,
 | 
						|
				  y_off - pDrawable->y,
 | 
						|
				  pPicture->pCompositeClip);
 | 
						|
    
 | 
						|
	    pPicturePrivate->serialNumber = pDrawable->serialNumber;
 | 
						|
	    pPicturePrivate->stateChanges &= ~(CPClipXOrigin | CPClipYOrigin | CPClipMask);
 | 
						|
	}
 | 
						|
 | 
						|
	CopyPicture(pPicture, pPicturePrivate->stateChanges, pBackingPicture);
 | 
						|
 | 
						|
	ValidatePicture (pBackingPicture);
 | 
						|
    }
 | 
						|
    cwPsWrap(ValidatePicture, cwValidatePicture);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cwComposite (CARD8	op,
 | 
						|
	     PicturePtr pSrcPicture,
 | 
						|
	     PicturePtr pMskPicture,
 | 
						|
	     PicturePtr pDstPicture,
 | 
						|
	     INT16	xSrc,
 | 
						|
	     INT16	ySrc,
 | 
						|
	     INT16	xMsk,
 | 
						|
	     INT16	yMsk,
 | 
						|
	     INT16	xDst,
 | 
						|
	     INT16	yDst,
 | 
						|
	     CARD16	width,
 | 
						|
	     CARD16	height)
 | 
						|
{
 | 
						|
    ScreenPtr	pScreen = pDstPicture->pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    cwSrcPictureDecl;
 | 
						|
    cwMskPictureDecl;
 | 
						|
    cwDstPictureDecl;
 | 
						|
    
 | 
						|
    cwPsUnwrap(Composite);
 | 
						|
    (*ps->Composite) (op, pBackingSrcPicture, pBackingMskPicture, pBackingDstPicture,
 | 
						|
		      xSrc + src_picture_x_off, ySrc + src_picture_y_off,
 | 
						|
		      xMsk + msk_picture_x_off, yMsk + msk_picture_y_off,
 | 
						|
		      xDst + dst_picture_x_off, yDst + dst_picture_y_off,
 | 
						|
		      width, height);
 | 
						|
    cwPsWrap(Composite, cwComposite);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cwCompositeRects (CARD8		op,
 | 
						|
		  PicturePtr	pDstPicture,
 | 
						|
		  xRenderColor  *color,
 | 
						|
		  int		nRect,
 | 
						|
		  xRectangle	*rects)
 | 
						|
{
 | 
						|
    ScreenPtr	pScreen = pDstPicture->pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    cwDstPictureDecl;
 | 
						|
    int i;
 | 
						|
    
 | 
						|
    cwPsUnwrap(CompositeRects);
 | 
						|
    for (i = 0; i < nRect; i++)
 | 
						|
    {
 | 
						|
	rects[i].x += dst_picture_x_off;
 | 
						|
	rects[i].y += dst_picture_y_off;
 | 
						|
    }
 | 
						|
    (*ps->CompositeRects) (op, pBackingDstPicture, color, nRect, rects);
 | 
						|
    cwPsWrap(CompositeRects, cwCompositeRects);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cwTrapezoids (CARD8	    op,
 | 
						|
	      PicturePtr    pSrcPicture,
 | 
						|
	      PicturePtr    pDstPicture,
 | 
						|
	      PictFormatPtr maskFormat,
 | 
						|
	      INT16	    xSrc,
 | 
						|
	      INT16	    ySrc,
 | 
						|
	      int	    ntrap,
 | 
						|
	      xTrapezoid    *traps)
 | 
						|
{
 | 
						|
    ScreenPtr	pScreen = pDstPicture->pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    cwSrcPictureDecl;
 | 
						|
    cwDstPictureDecl;
 | 
						|
    int i;
 | 
						|
    
 | 
						|
    cwPsUnwrap(Trapezoids);
 | 
						|
    if (dst_picture_x_off || dst_picture_y_off) {
 | 
						|
	for (i = 0; i < ntrap; i++)
 | 
						|
	{
 | 
						|
	    traps[i].top += dst_picture_y_off << 16;
 | 
						|
	    traps[i].bottom += dst_picture_y_off << 16;
 | 
						|
	    traps[i].left.p1.x += dst_picture_x_off << 16;
 | 
						|
	    traps[i].left.p1.y += dst_picture_y_off << 16;
 | 
						|
	    traps[i].left.p2.x += dst_picture_x_off << 16;
 | 
						|
	    traps[i].left.p2.y += dst_picture_y_off << 16;
 | 
						|
	    traps[i].right.p1.x += dst_picture_x_off << 16;
 | 
						|
	    traps[i].right.p1.y += dst_picture_y_off << 16;
 | 
						|
	    traps[i].right.p2.x += dst_picture_x_off << 16;
 | 
						|
	    traps[i].right.p2.y += dst_picture_y_off << 16;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    (*ps->Trapezoids) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat,
 | 
						|
		       xSrc + src_picture_x_off, ySrc + src_picture_y_off,
 | 
						|
		       ntrap, traps);
 | 
						|
    cwPsWrap(Trapezoids, cwTrapezoids);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cwTriangles (CARD8	    op,
 | 
						|
	     PicturePtr	    pSrcPicture,
 | 
						|
	     PicturePtr	    pDstPicture,
 | 
						|
	     PictFormatPtr  maskFormat,
 | 
						|
	     INT16	    xSrc,
 | 
						|
	     INT16	    ySrc,
 | 
						|
	     int	    ntri,
 | 
						|
	     xTriangle	   *tris)
 | 
						|
{
 | 
						|
    ScreenPtr	pScreen = pDstPicture->pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    cwSrcPictureDecl;
 | 
						|
    cwDstPictureDecl;
 | 
						|
    int i;
 | 
						|
    
 | 
						|
    cwPsUnwrap(Triangles);
 | 
						|
    if (dst_picture_x_off || dst_picture_y_off) {
 | 
						|
	for (i = 0; i < ntri; i++)
 | 
						|
	{
 | 
						|
	    tris[i].p1.x += dst_picture_x_off << 16;
 | 
						|
	    tris[i].p1.y += dst_picture_y_off << 16;
 | 
						|
	    tris[i].p2.x += dst_picture_x_off << 16;
 | 
						|
	    tris[i].p2.y += dst_picture_y_off << 16;
 | 
						|
	    tris[i].p3.x += dst_picture_x_off << 16;
 | 
						|
	    tris[i].p3.y += dst_picture_y_off << 16;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    (*ps->Triangles) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat,
 | 
						|
		      xSrc + src_picture_x_off, ySrc + src_picture_y_off,
 | 
						|
		      ntri, tris);
 | 
						|
    cwPsWrap(Triangles, cwTriangles);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cwTriStrip (CARD8	    op,
 | 
						|
	    PicturePtr	    pSrcPicture,
 | 
						|
	    PicturePtr	    pDstPicture,
 | 
						|
	    PictFormatPtr   maskFormat,
 | 
						|
	    INT16	    xSrc,
 | 
						|
	    INT16	    ySrc,
 | 
						|
	    int		    npoint,
 | 
						|
	    xPointFixed    *points)
 | 
						|
{
 | 
						|
    ScreenPtr	pScreen = pDstPicture->pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    cwSrcPictureDecl;
 | 
						|
    cwDstPictureDecl;
 | 
						|
    int i;
 | 
						|
 | 
						|
    cwPsUnwrap(TriStrip);
 | 
						|
    if (dst_picture_x_off || dst_picture_y_off) {
 | 
						|
	for (i = 0; i < npoint; i++)
 | 
						|
	{
 | 
						|
	    points[i].x += dst_picture_x_off << 16;
 | 
						|
	    points[i].y += dst_picture_y_off << 16;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    (*ps->TriStrip) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat,
 | 
						|
		     xSrc + src_picture_x_off, ySrc + src_picture_y_off,
 | 
						|
		     npoint, points);
 | 
						|
    cwPsWrap(TriStrip, cwTriStrip);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
cwTriFan (CARD8		 op,
 | 
						|
	  PicturePtr	 pSrcPicture,
 | 
						|
	  PicturePtr	 pDstPicture,
 | 
						|
	  PictFormatPtr  maskFormat,
 | 
						|
	  INT16		 xSrc,
 | 
						|
	  INT16		 ySrc,
 | 
						|
	  int		 npoint,
 | 
						|
	  xPointFixed   *points)
 | 
						|
{
 | 
						|
    ScreenPtr	pScreen = pDstPicture->pDrawable->pScreen;
 | 
						|
    cwPsDecl(pScreen);
 | 
						|
    cwSrcPictureDecl;
 | 
						|
    cwDstPictureDecl;
 | 
						|
    int i;
 | 
						|
 | 
						|
    cwPsUnwrap(TriFan);
 | 
						|
    if (dst_picture_x_off || dst_picture_y_off) {
 | 
						|
	for (i = 0; i < npoint; i++)
 | 
						|
	{
 | 
						|
	    points[i].x += dst_picture_x_off << 16;
 | 
						|
	    points[i].y += dst_picture_y_off << 16;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    (*ps->TriFan) (op, pBackingSrcPicture, pBackingDstPicture, maskFormat,
 | 
						|
		   xSrc + src_picture_x_off, ySrc + src_picture_y_off,
 | 
						|
		   npoint, points);
 | 
						|
    cwPsWrap(TriFan, cwTriFan);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
cwInitializeRender (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    cwPsDecl (pScreen);
 | 
						|
 | 
						|
    cwPsWrap(DestroyPicture, cwDestroyPicture);
 | 
						|
    cwPsWrap(ChangePicture, cwChangePicture);
 | 
						|
    cwPsWrap(ValidatePicture, cwValidatePicture);
 | 
						|
    cwPsWrap(Composite, cwComposite);
 | 
						|
    cwPsWrap(CompositeRects, cwCompositeRects);
 | 
						|
    cwPsWrap(Trapezoids, cwTrapezoids);
 | 
						|
    cwPsWrap(Triangles, cwTriangles);
 | 
						|
    cwPsWrap(TriStrip, cwTriStrip);
 | 
						|
    cwPsWrap(TriFan, cwTriFan);
 | 
						|
    /* There is no need to wrap AddTraps as far as we can tell.  AddTraps can
 | 
						|
     * only be done on alpha-only pictures, and we won't be getting
 | 
						|
     * alpha-only window pictures, so there's no need to translate.
 | 
						|
     */
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
cwFiniRender (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    cwPsDecl (pScreen);
 | 
						|
 | 
						|
    cwPsUnwrap(DestroyPicture);
 | 
						|
    cwPsUnwrap(ChangePicture);
 | 
						|
    cwPsUnwrap(ValidatePicture);
 | 
						|
    cwPsUnwrap(Composite);
 | 
						|
    cwPsUnwrap(CompositeRects);
 | 
						|
    cwPsUnwrap(Trapezoids);
 | 
						|
    cwPsUnwrap(Triangles);
 | 
						|
    cwPsUnwrap(TriStrip);
 | 
						|
    cwPsUnwrap(TriFan);
 | 
						|
}
 | 
						|
 |