void ExtractBrushEntityShadowCasters()
{
	for ( int i = 0; i < num_entities; i++ )
	{
		if ( IntForKey( &entities[i], "vrad_brush_cast_shadows" ) != 0 )
		{
			Vector origin;
			QAngle angles;
			GetVectorForKey( &entities[i], "origin", origin );
			GetAnglesForKey( &entities[i], "angles", angles );
			VMatrix xform;
			xform.SetupMatrixOrgAngles( origin, angles );
			AddBrushes( BrushmodelForEntity( &entities[i] ), xform );
		}
	}
}

// trace.c

#include "vrad.h"
#include "trace.h"
#include "Cmodel.h"
#include "mathlib/vmatrix.h"

class CToolTrace : public CBaseTrace
{
public:
	CToolTrace() {}

	Vector		mins;
	Vector		maxs;
	Vector		extents;

	texinfo_t	*surface;

	qboolean	ispoint;

private:
	 CToolTrace( const CToolTrace& );
};

// 1/32 epsilon to keep floating point happy
#define	DIST_EPSILON	(0.03125)

// JAYHL2: This used to be -1, but that caused lots of epsilon issues
// around slow sloping planes.  Perhaps Quake2 limited maps to a certain
// slope / angle on walkable ground.  It has to be a negative number
// so that the tests work out.
#define		NEVER_UPDATED		-9999

bool DM_RayDispIntersectTest( CVRADDispColl *pTree, Vector& rayStart, Vector& rayEnd, CToolTrace *pTrace );
void DM_ClipBoxToBrush( CToolTrace *trace, const Vector & mins, const Vector & maxs, const Vector& p1, const Vector& p2, dbrush_t *brush );

float TraceLeafBrushes( int leafIndex, const Vector &start, const Vector &end, CBaseTrace &traceOut )
{
	dleaf_t *pLeaf = dleafs + leafIndex;
	CToolTrace trace;
	memset( &trace, 0, sizeof(trace) );
	trace.ispoint = true;
	trace.startsolid = false;
	trace.fraction = 1.0;

	for ( int i = 0; i < pLeaf->numleafbrushes; i++ )
	{
		int brushnum = dleafbrushes[pLeaf->firstleafbrush+i];
		dbrush_t *b = &dbrushes[brushnum];
		if ( !(b->contents & MASK_OPAQUE))
			continue;

		Vector zeroExtents = vec3_origin;
		DM_ClipBoxToBrush( &trace, zeroExtents, zeroExtents, start, end, b);
		if ( trace.fraction != 1.0 || trace.startsolid )
		{
			if ( trace.startsolid )
				trace.fraction = 0.0f;
			traceOut = trace;
			return trace.fraction;
		}
	}
	traceOut = trace;
	return 1.0f;
}

DispTested_t s_DispTested[MAX_TOOL_THREADS+1];

// this just uses the average coverage for the triangle
class CCoverageCount : public ITransparentTriangleCallback
{
public:
	CCoverageCount()
	{
		m_coverage = Four_Zeros;
	}

	virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, fltx4 *pHitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID )
	{
		float color = g_RtEnv.GetTriangleColor( hitID ).x;
		m_coverage = AddSIMD( m_coverage, AndSIMD ( *pHitMask, ReplicateX4 ( color ) ) );
		m_coverage = MinSIMD( m_coverage, Four_Ones );

		fltx4 onesMask = CmpEqSIMD( m_coverage, Four_Ones );

		// we should continue if the ones that hit the triangle have onesMask set to zero
		// so hitMask & onesMask != hitMask
		// so hitMask & onesMask == hitMask means we're done
		// so ts(hitMask & onesMask == hitMask) != 0xF says go on
		return 0xF != TestSignSIMD ( CmpEqSIMD ( AndSIMD( *pHitMask, onesMask ), *pHitMask ) );
	}

	fltx4 GetCoverage()
	{
		return m_coverage;
	}

	fltx4 GetFractionVisible()
	{
		return SubSIMD ( Four_Ones, m_coverage );
	}

	fltx4 m_coverage;
};

// this will sample the texture to get a coverage at the ray intersection point
class CCoverageCountTexture : public CCoverageCount
{
public:
	virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, fltx4 *pHitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID )
	{
		int sign = TestSignSIMD( *pHitMask );
		float addedCoverage[4];
		for ( int s = 0; s < 4; s++)
		{
			addedCoverage[s] = 0.0f;
			if ( ( sign >> s) & 0x1 )
			{
				addedCoverage[s] = ComputeCoverageFromTexture( b0->m128_f32[s], b1->m128_f32[s], b2->m128_f32[s], hitID );
			}
		}
		m_coverage = AddSIMD( m_coverage, LoadUnalignedSIMD( addedCoverage ) );
		m_coverage = MinSIMD( m_coverage, Four_Ones );
		fltx4 onesMask = CmpEqSIMD( m_coverage, Four_Ones );

		// we should continue if the ones that hit the triangle have onesMask set to zero
		// so hitMask & onesMask != hitMask
		// so hitMask & onesMask == hitMask means we're done
		// so ts(hitMask & onesMask == hitMask) != 0xF says go on
		return 0xF != TestSignSIMD ( CmpEqSIMD ( AndSIMD( *pHitMask, onesMask ), *pHitMask ) );
	}
};

void TestLine( const FourVectors& start, const FourVectors& stop,
               fltx4 *pFractionVisible, int static_prop_index_to_ignore )
{
	FourRays myrays;
	myrays.origin = start;
	myrays.direction = stop;
	myrays.direction -= myrays.origin;
	fltx4 len = myrays.direction.length();
	myrays.direction *= ReciprocalSIMD( len );

	RayTracingResult rt_result;
	CCoverageCountTexture coverageCallback;

	g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_index_to_ignore, g_bTextureShadows ? &coverageCallback : 0 );

	// Assume we can see the targets unless we get hits
	float visibility[4];
	for ( int i = 0; i < 4; i++ )
	{
		visibility[i] = 1.0f;
		if ( ( rt_result.HitIds[i] != -1 ) &&
		     ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) )
		{
			visibility[i] = 0.0f;
		}
	}
	*pFractionVisible = LoadUnalignedSIMD( visibility );
	if ( g_bTextureShadows )
		*pFractionVisible = MinSIMD( *pFractionVisible, coverageCallback.GetFractionVisible() );
}

void TestLine_IgnoreSky( const FourVectors& start, const FourVectors& stop,
						 fltx4 *pFractionVisible, int static_prop_index_to_ignore )
{
	FourRays myrays;
	myrays.origin = start;
	myrays.direction = stop;
	myrays.direction -= myrays.origin;
	fltx4 len = myrays.direction.length();
	myrays.direction *= ReciprocalSIMD( len );

	RayTracingResult rt_result;
	CCoverageCountTexture coverageCallback;

	g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_index_to_ignore, g_bTextureShadows ? &coverageCallback : 0 );

	// Assume we can see the targets unless we get hits
	float visibility[4];
	for ( int i = 0; i < 4; i++ )
	{
		visibility[i] = 1.0f;
		if ( ( rt_result.HitIds[i] != -1 ) &&
			 ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) )
		{
			int id = g_RtEnv.OptimizedTriangleList[rt_result.HitIds[i]].m_Data.m_IntersectData.m_nTriangleID;
			if ( !( id & TRACE_ID_SKY ) )
			{
				visibility[i] = 0.0f;
			}
		}
	}
	*pFractionVisible = LoadUnalignedSIMD( visibility );
	if ( g_bTextureShadows )
		*pFractionVisible = MinSIMD( *pFractionVisible, coverageCallback.GetFractionVisible() );
}

void TestLine_LightBlockers( const FourVectors& start, const FourVectors& stop,
							 fltx4 *pFractionVisible )
{
	FourRays myrays;
	myrays.origin = start;
	myrays.direction = stop;
	myrays.direction -= myrays.origin;
	fltx4 len = myrays.direction.length();
	myrays.direction *= ReciprocalSIMD( len );

	RayTracingResult rt_result;

	g_RtEnv_LightBlockers.Trace4Rays( myrays, Four_Zeros, len, &rt_result, -1, NULL );

	// Assume we can see the targets unless we get hits
	float visibility[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	if ( (rt_result.HitIds[0] != -1) &&
		 (rt_result.HitDistance.m128_f32[0] < len.m128_f32[0]) )
	{
		fltx4 dotRaySurfaceN = rt_result.surface_normal * myrays.direction;
		if ( dotRaySurfaceN.m128_f32[0] > 0.0f )
		{
			visibility[0] = 0.0f;
		}
	}
	*pFractionVisible = LoadUnalignedSIMD( visibility );
}

/*
================
DM_ClipBoxToBrush
================
*/
void DM_ClipBoxToBrush( CToolTrace *trace, const Vector& mins, const Vector& maxs, const Vector& p1, const Vector& p2,
						dbrush_t *brush)
{
	dplane_t	*plane, *clipplane;
	float		dist;
	Vector		ofs;
	float		d1, d2;
	float		f;
	dbrushside_t	*side, *leadside;

	if (!brush->numsides)
		return;

	float enterfrac = NEVER_UPDATED;
	float leavefrac = 1.f;
	clipplane = NULL;

	bool getout = false;
	bool startout = false;
	leadside = NULL;

	// Loop interchanged, so we don't have to check trace->ispoint every side.
	if ( !trace->ispoint )
	{
		for (int i=0 ; i<brush->numsides ; ++i)
		{
			side = &dbrushsides[brush->firstside+i];
			plane = dplanes + side->planenum;

			// general box case
			// push the plane out apropriately for mins/maxs

			// FIXME: use signbits into 8 way lookup for each mins/maxs
			ofs.x = (plane->normal.x < 0) ? maxs.x : mins.x;
			ofs.y = (plane->normal.y < 0) ? maxs.y : mins.y;
			ofs.z = (plane->normal.z < 0) ? maxs.z : mins.z;
				// Set signmask to either 0 if the sign is negative, or 0xFFFFFFFF is the sign is positive:

			dist = DotProduct (ofs, plane->normal);
			dist = plane->dist - dist;

			d1 = DotProduct (p1, plane->normal) - dist;
			d2 = DotProduct (p2, plane->normal) - dist;

			// if completely in front of face, no intersection
			if (d1 > 0 && d2 > 0)
				return;

			if (d2 > 0)
				getout = true;	// endpoint is not in solid
			if (d1 > 0)
				startout = true;

			if (d1 <= 0 && d2 <= 0)
				continue;

			// crosses face
			if (d1 > d2)
			{	// enter
				f = (d1-DIST_EPSILON) / (d1-d2);
				if (f > enterfrac)
				{
					enterfrac = f;
					clipplane = plane;
					leadside = side;
				}
			}
			else
			{	// leave
				f = (d1+DIST_EPSILON) / (d1-d2);
				if (f < leavefrac)
					leavefrac = f;
			}
		}
	}
	else
	{
		for (int i=0 ; i<brush->numsides ; ++i)
		{
			side = &dbrushsides[brush->firstside+i];
			plane = dplanes + side->planenum;

			// special point case
			// don't ray trace against bevel planes
			if( side->bevel == 1 )
				continue;

			dist = plane->dist;
			d1 = DotProduct (p1, plane->normal) - dist;
			d2 = DotProduct (p2, plane->normal) - dist;

			// if completely in front of face, no intersection
			if (d1 > 0 && d2 > 0)
				return;

			if (d2 > 0)
				getout = true;	// endpoint is not in solid
			if (d1 > 0)
				startout = true;

			if (d1 <= 0 && d2 <= 0)
				continue;

			// crosses face
			if (d1 > d2)
			{	// enter
				f = (d1-DIST_EPSILON) / (d1-d2);
				if (f > enterfrac)
				{
					enterfrac = f;
					clipplane = plane;
					leadside = side;
				}
			}
			else
			{	// leave
				f = (d1+DIST_EPSILON) / (d1-d2);
				if (f < leavefrac)
					leavefrac = f;
			}
		}
	}

	if (!startout)
	{	// original point was inside brush
		trace->startsolid = true;
		if (!getout)
			trace->allsolid = true;
		return;
	}
	if (enterfrac < leavefrac)
	{
		if (enterfrac > NEVER_UPDATED && enterfrac < trace->fraction)
		{
			if (enterfrac < 0)
				enterfrac = 0;
			trace->fraction = enterfrac;
			trace->plane.dist = clipplane->dist;
			trace->plane.normal = clipplane->normal;
			trace->plane.type = clipplane->type;
			if (leadside->texinfo!=-1)
				trace->surface = &texinfo[leadside->texinfo];
			else
				trace->surface = 0;
			trace->contents = brush->contents;
		}
	}
}

void TestLine_DoesHitSky( FourVectors const& start, FourVectors const& stop,
	fltx4 *pFractionVisible, bool canRecurse, int static_prop_to_skip, bool bDoDebug )
{
	FourRays myrays;
	myrays.origin = start;
	myrays.direction = stop;
	myrays.direction -= myrays.origin;
	fltx4 len = myrays.direction.length();
	myrays.direction *= ReciprocalSIMD( len );
	RayTracingResult rt_result;
	CCoverageCountTexture coverageCallback;

	g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_to_skip, g_bTextureShadows? &coverageCallback : 0);

	if ( bDoDebug )
	{
		WriteTrace( "trace.txt", myrays, rt_result );
	}

	float aOcclusion[4];
	for ( int i = 0; i < 4; i++ )
	{
		aOcclusion[i] = 0.0f;
		if ( ( rt_result.HitIds[i] != -1 ) &&
		     ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) )
		{
			int id = g_RtEnv.OptimizedTriangleList[rt_result.HitIds[i]].m_Data.m_IntersectData.m_nTriangleID;
			if ( !( id & TRACE_ID_SKY ) )
				aOcclusion[i] = 1.0f;
		}
	}
	fltx4 occlusion = LoadUnalignedSIMD( aOcclusion );
	if (g_bTextureShadows)
		occlusion = MaxSIMD ( occlusion, coverageCallback.GetCoverage() );

	bool fullyOccluded = ( TestSignSIMD( CmpGeSIMD( occlusion, Four_Ones ) ) == 0xF );

	// if we hit sky, and we're not in a sky camera's area, try clipping into the 3D sky boxes
	if ( (! fullyOccluded) && canRecurse && (! g_bNoSkyRecurse ) )
	{
		FourVectors dir = stop;
		dir -= start;
		dir.VectorNormalize();

		int leafIndex = -1;
		leafIndex = PointLeafnum( start.Vec( 0 ) );
		if ( leafIndex >= 0 )
		{
			int area = dleafs[leafIndex].area;
			if (area >= 0 && area < numareas)
			{
				if (area_sky_cameras[area] < 0)
				{
					int cam;
					for (cam = 0; cam < num_sky_cameras; ++cam)
					{
						FourVectors skystart, skytrans, skystop;
						skystart.DuplicateVector( sky_cameras[cam].origin );
						skystop = start;
						skystop *= sky_cameras[cam].world_to_sky;
						skystart += skystop;

						skystop = dir;
						skystop *= MAX_TRACE_LENGTH;
						skystop += skystart;
						TestLine_DoesHitSky ( skystart, skystop, pFractionVisible, false, static_prop_to_skip, bDoDebug );
						occlusion = AddSIMD ( occlusion, Four_Ones );
						occlusion = SubSIMD ( occlusion, *pFractionVisible );
					}
				}
			}
		}
	}

	occlusion = MaxSIMD( occlusion, Four_Zeros );
	occlusion = MinSIMD( occlusion, Four_Ones );
	*pFractionVisible = SubSIMD( Four_Ones, occlusion );
}

int PointLeafnum_r( const Vector &point, int ndxNode )
{
	// while loop here is to avoid recursion overhead
	while( ndxNode >= 0 )
	{
		dnode_t *pNode = dnodes + ndxNode;
		dplane_t *pPlane = dplanes + pNode->planenum;

		float dist;
		if( pPlane->type < 3 )
		{
			dist = point[pPlane->type] - pPlane->dist;
		}
		else
		{
			dist = DotProduct( pPlane->normal, point ) - pPlane->dist;
		}

		if( dist < 0.0f )
		{
			ndxNode = pNode->children[1];
		}
		else
		{
			ndxNode = pNode->children[0];
		}
	}

	return ( -1 - ndxNode );
}

int PointLeafnum( const Vector &point )
{
	return PointLeafnum_r( point, 0 );
}

// this iterates the list of entities looking for _vradshadows 1
// each brush entity containing this key is added to the raytracing environment
// as a triangle soup model.

dmodel_t *BrushmodelForEntity( entity_t *pEntity )
{
	const char *pModelname = ValueForKey( pEntity, "model" );
	if ( Q_strlen(pModelname) > 1 )
	{
		int modelIndex = atol( pModelname + 1 );
		if ( modelIndex > 0 && modelIndex < nummodels )
		{
			return &dmodels[modelIndex];
		}
	}
	return NULL;
}

// Add one that casts textureshadows
void AddTexturedBrushWinding( winding_t *w, const VMatrix &xform, texinfo_t *tx, int shadowMaterialIndex )
{
	Vector2D uv[MAX_POINTS_ON_WINDING];
	int mappingWidth = 32;
	int mappingHeight = 32;
	GetShadowTextureMapping( shadowMaterialIndex, &mappingWidth, &mappingHeight );

	for ( int j = 0; j < w->numpoints; j++ )
	{
		// base texture coordinate
		uv[j].x = DotProduct( w->p[j].Base(), tx->textureVecsTexelsPerWorldUnits[0] ) +
			tx->textureVecsTexelsPerWorldUnits[0][3];
		uv[j].x /= float(mappingWidth);

		uv[j].y = DotProduct( w->p[j].Base(), tx->textureVecsTexelsPerWorldUnits[1] ) +
			tx->textureVecsTexelsPerWorldUnits[1][3];
		uv[j].y /= float(mappingHeight);
	}
	Vector v0, v1, v2;

	for ( int j = 2; j < w->numpoints; j++ )
	{
		v0 = xform.VMul4x3(w->p[0]);
		v1 = xform.VMul4x3(w->p[j-1]);
		v2 = xform.VMul4x3(w->p[j]);
		float coverage = ComputeCoverageForTriangle(shadowMaterialIndex, uv[0], uv[j-1], uv[j] );
		int index = -1;
		unsigned short flags = 0;
		Vector fullCoverage(0,0,1);
		if ( coverage < 1.0 )
		{
			index = AddShadowTextureTriangle( shadowMaterialIndex, uv[0], uv[j-1], uv[j] );
			flags = FCACHETRI_TRANSPARENT;
			fullCoverage.x = coverage;
		}

		g_RtEnv.AddTriangle(TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage, flags, index);
	}
}

void AddBrushToRaytraceEnvironment( dbrush_t *pBrush, const VMatrix &xform )
{
	int materialIndexList[256];
	bool bTextureShadows = false;

	if ( !( pBrush->contents & (MASK_OPAQUE) ) && !(g_bTextureShadows && (pBrush->contents & CONTENTS_GRATE)) )
		return;

	if ( pBrush->contents & CONTENTS_LADDER )
		return;

	// load any transparent textures for shadows
	if ( g_bTextureShadows && (pBrush->contents & CONTENTS_GRATE) && pBrush->numsides < ARRAYSIZE(materialIndexList) )
	{
		for (int i = 0; i < pBrush->numsides; i++ )
		{
			dbrushside_t *side = &dbrushsides[pBrush->firstside + i];
			texinfo_t *tx = &texinfo[side->texinfo];
			dtexdata_t *pTexData = &dtexdata[tx->texdata];
			const char *pMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID );
			materialIndexList[i] = LoadShadowTexture( pMaterialName );
			if ( materialIndexList[i] >= 0 )
			{
				bTextureShadows = true;
			}
		}
	}
	Vector v0, v1, v2;

	for (int i = 0; i < pBrush->numsides; i++ )
	{
		dbrushside_t *side = &dbrushsides[pBrush->firstside + i];
		dplane_t *plane = &dplanes[side->planenum];
		texinfo_t *tx = &texinfo[side->texinfo];
		winding_t *w = BaseWindingForPlane (plane->normal, plane->dist);
		bool bIsLightBlocker = false;

		if ( tx->flags & SURF_SKY || side->dispinfo )
			continue;

		if ( ( pBrush->contents & ( CONTENTS_OPAQUE | CONTENTS_SOLID ) ) && ( tx->flags & SURF_NODRAW ) )
		{
			bIsLightBlocker = true;
		}

		for (int j=0 ; j<pBrush->numsides && w; j++)
		{
			if (i == j)
				continue;
			dbrushside_t *pOtherSide = &dbrushsides[pBrush->firstside + j];
			if (pOtherSide->bevel)
				continue;
			plane = &dplanes[pOtherSide->planenum^1];
			ChopWindingInPlace (&w, plane->normal, plane->dist, 0);
		}
		if ( w )
		{
			if ( bTextureShadows && materialIndexList[i] >= 0 )
			{
				AddTexturedBrushWinding( w, xform, tx, materialIndexList[i] );
			}
			else
			{
				// opaque
				Vector fullCoverage(1,1,1);
				for ( int j = 2; j < w->numpoints; j++ )
				{
					v0 = xform.VMul4x3(w->p[0]);
					v1 = xform.VMul4x3(w->p[j-1]);
					v2 = xform.VMul4x3(w->p[j]);
					g_RtEnv.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage );

					// light blockers
					if ( bIsLightBlocker )
					{
						g_RtEnv_LightBlockers.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage );
						g_RtEnv_RadiosityPatches.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage );
					}
				}
			}
			FreeWinding( w );
		}
	}
}

// recurse the bsp and build a list of brushes at the leaves under this node
void GetBrushes_r( int node, CUtlVector<int> &list )
{
	if ( node < 0 )
	{
		int leafIndex = -1 - node;
		// Add the solids in the leaf
		for ( int i = 0; i < dleafs[leafIndex].numleafbrushes; i++ )
		{
			int brushIndex = dleafbrushes[dleafs[leafIndex].firstleafbrush + i];
			if ( list.Find(brushIndex) < 0 )
			{
				list.AddToTail( brushIndex );
			}
		}
	}
	else
	{
		// recurse
		dnode_t *pnode = dnodes + node;

		GetBrushes_r( pnode->children[0], list );
		GetBrushes_r( pnode->children[1], list );
	}
}

void AddBrushes( dmodel_t *pModel, const VMatrix &xform )
{
	if ( pModel )
	{
		CUtlVector<int> brushList;
		GetBrushes_r( pModel->headnode, brushList );
		for ( int i = 0; i < brushList.Count(); i++ )
		{
			int ndxBrush = brushList[i];
			AddBrushToRaytraceEnvironment( &dbrushes[ndxBrush], xform );
		}
	}
}

// Adds the brush entities that cast shadows to the raytrace environment

void AddBrushesForRayTrace( void )
{
	if ( !nummodels )
		return;

	VMatrix identity;
	identity.Identity();

	CUtlVector<int> brushList;
	GetBrushes_r ( dmodels[0].headnode, brushList );

	for ( int i = 0; i < brushList.Count(); i++ )
	{
		dbrush_t *brush = &dbrushes[brushList[i]];
		AddBrushToRaytraceEnvironment ( brush, identity );
	}

	for ( int i = 0; i < dmodels[0].numfaces; i++ )
	{
		int ndxFace = dmodels[0].firstface + i;
		dface_t *face = &g_pFaces[ndxFace];

		texinfo_t *tx = &texinfo[face->texinfo];
		if ( !( tx->flags & SURF_SKY ) )
			continue;

		Vector points[MAX_POINTS_ON_WINDING];

		for ( int j = 0; j < face->numedges; j++ )
		{
			if ( j >= MAX_POINTS_ON_WINDING )
				Error( "***** ERROR! MAX_POINTS_ON_WINDING reached!" );

			if ( face->firstedge + j >= ARRAYSIZE( dsurfedges ) )
				Error( "***** ERROR! face->firstedge + j >= ARRAYSIZE( dsurfedges )!" );

			int surfEdge = dsurfedges[face->firstedge + j];
			unsigned short v;

			if (surfEdge < 0)
				v = dedges[-surfEdge].v[1];
			else
				v = dedges[surfEdge].v[0];

			if ( v >= ARRAYSIZE( dvertexes ) )
				Error( "***** ERROR! v(%u) >= ARRAYSIZE( dvertexes(%d) )!", ( unsigned int )v, ARRAYSIZE( dvertexes ) );

			dvertex_t *dv = &dvertexes[v];
			points[j] = dv->point;
		}

		for ( int j = 2; j < face->numedges; j++ )
		{
			Vector fullCoverage;
			fullCoverage.x = 1.0f;
			g_RtEnv.AddTriangle ( TRACE_ID_SKY, points[0], points[j - 1], points[j], fullCoverage );
		}
	}
}


#if defined(BOOST_INTERPROCESS_MAPPED_FILES)

#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <cstdio>
#include <string>
#include "get_process_id_name.hpp"

using namespace boost::interprocess;

inline std::string get_filename()
{
   std::string ret (ipcdetail::get_temporary_path());
   ret += "/";
   ret += test::get_process_id_name();
   return ret;
}

int main ()
{
   const int FileSize          = 65536*10;
   std::string filename(get_filename());
   const char *FileName = filename.c_str();

   //STL compatible allocator object for memory-mapped file
   typedef allocator<int, managed_mapped_file::segment_manager>
      allocator_int_t;
   //A vector that uses that allocator
   typedef boost::interprocess::vector<int, allocator_int_t> MyVect;

   {
      //Remove the file it is already created
      file_mapping::remove(FileName);

      const int max              = 100;
      void *array[max];
      //Named allocate capable shared memory allocator
      managed_mapped_file mfile(create_only, FileName, FileSize);

      int i;
      //Let's allocate some memory
      for(i = 0; i < max; ++i){
         array[i] = mfile.allocate(i+1);
      }

      //Deallocate allocated memory
      for(i = 0; i < max; ++i){
         mfile.deallocate(array[i]);
      }
   }

   {
      //Remove the file it is already created
      file_mapping::remove(FileName);

      //Named allocate capable memory mapped file managed memory class
      managed_mapped_file mfile(create_only, FileName, FileSize);

      //Construct the STL-like allocator with the segment manager
      const allocator_int_t myallocator (mfile.get_segment_manager());

      //Construct vector
      MyVect *mfile_vect = mfile.construct<MyVect> ("MyVector") (myallocator);

      //Test that vector can be found via name
      if(mfile_vect != mfile.find<MyVect>("MyVector").first)
         return -1;

      //Destroy and check it is not present
      mfile.destroy<MyVect> ("MyVector");
      if(0 != mfile.find<MyVect>("MyVector").first)
         return -1;

      //Construct a vector in the memory-mapped file
      mfile_vect = mfile.construct<MyVect> ("MyVector") (myallocator);

      //Flush cached data from memory-mapped file to disk
      mfile.flush();
   }
   {
      //Map preexisting file again in memory
      managed_mapped_file mfile(open_only, FileName);

      //Check vector is still there
      MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first;
      if(!mfile_vect)
         return -1;
   }

   {
      {
         //Map preexisting file again in copy-on-write
         managed_mapped_file mfile(open_copy_on_write, FileName);

         //Check vector is still there
         MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first;
         if(!mfile_vect)
            return -1;

         //Erase vector
         mfile.destroy_ptr(mfile_vect);

         //Make sure vector is erased
         mfile_vect = mfile.find<MyVect>("MyVector").first;
         if(mfile_vect)
            return -1;
      }
      //Now check vector is still in the file
      {
         //Map preexisting file again in copy-on-write
         managed_mapped_file mfile(open_copy_on_write, FileName);

         //Check vector is still there
         MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first;
         if(!mfile_vect)
            return -1;
      }
   }
   {
      //Map preexisting file again in copy-on-write
      managed_mapped_file mfile(open_read_only, FileName);

      //Check vector is still there
      MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first;
      if(!mfile_vect)
         return -1;
   }
   {
      managed_mapped_file::size_type old_free_memory;
      {
         //Map preexisting file again in memory
         managed_mapped_file mfile(open_only, FileName);
         old_free_memory = mfile.get_free_memory();
      }

      //Now grow the file
      managed_mapped_file::grow(FileName, FileSize);

      //Map preexisting file again in memory
      managed_mapped_file mfile(open_only, FileName);

      //Check vector is still there
      MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first;
      if(!mfile_vect)
         return -1;

      if(mfile.get_size() != (FileSize*2))
         return -1;
      if(mfile.get_free_memory() <= old_free_memory)
         return -1;
   }
   {
      managed_mapped_file::size_type old_free_memory, next_free_memory,
                  old_file_size, next_file_size, final_file_size;
      {
         //Map preexisting file again in memory
         managed_mapped_file mfile(open_only, FileName);
         old_free_memory = mfile.get_free_memory();
         old_file_size   = mfile.get_size();
      }

      //Now shrink the file
      managed_mapped_file::shrink_to_fit(FileName);

      {
         //Map preexisting file again in memory
         managed_mapped_file mfile(open_only, FileName);
         next_file_size = mfile.get_size();

         //Check vector is still there
         MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first;
         if(!mfile_vect)
            return -1;

         next_free_memory = mfile.get_free_memory();
         if(next_free_memory >= old_free_memory)
            return -1;
         if(old_file_size <= next_file_size)
            return -1;
      }

      //Now destroy the vector
      {
         //Map preexisting file again in memory
         managed_mapped_file mfile(open_only, FileName);

         //Destroy and check it is not present
         mfile.destroy<MyVect>("MyVector");
         if(0 != mfile.find<MyVect>("MyVector").first)
            return -1;
      }

      //Now shrink the file
      managed_mapped_file::shrink_to_fit(FileName);
      {
         //Map preexisting file again in memory
         managed_mapped_file mfile(open_only, FileName);
         final_file_size = mfile.get_size();
         if(next_file_size <= final_file_size)
            return -1;
      }
      {
         //Now test move semantics
         managed_mapped_file original(open_only, FileName);
         managed_mapped_file move_ctor(boost::move(original));
         managed_mapped_file move_assign;
         move_assign = boost::move(move_ctor);
         move_assign.swap(original);
      }
   }

   file_mapping::remove(FileName);
   return 0;
}

#include <boost/interprocess/detail/config_end.hpp>

#else //#if defined(BOOST_INTERPROCESS_MAPPED_FILES)


//          Jiashun Zhu(example@nnthink.com)

#include <google/protobuf/descriptor.h>         // MethodDescriptor
#include <google/protobuf/message.h>            // Message
#include <gflags/gflags.h>
#include "butil/logging.h"                       // LOG()
#include "butil/time.h"
#include "butil/iobuf.h"                         // butil::IOBuf
#include "brpc/controller.h"               // Controller
#include "brpc/details/controller_private_accessor.h"
#include "brpc/socket.h"                   // Socket
#include "brpc/server.h"                   // Server
#include "brpc/details/server_private_accessor.h"
#include "brpc/span.h"
#include "brpc/redis.h"
#include "brpc/redis_command.h"
#include "brpc/policy/redis_protocol.h"

namespace brpc {

DECLARE_bool(enable_rpcz);
DECLARE_bool(usercode_in_pthread);

namespace policy {

DEFINE_bool(redis_verbose, false,
            "[DEBUG] Print EVERY redis request/response");

struct InputResponse : public InputMessageBase {
    bthread_id_t id_wait;
    RedisResponse response;

    // @InputMessageBase
    void DestroyImpl() {
        delete this;
    }
};

// This class is as parsing_context in socket.
class RedisConnContext : public Destroyable  {
public:
    explicit RedisConnContext(const RedisService* rs)
        : redis_service(rs)
        , batched_size(0) {}

    ~RedisConnContext();
    // @Destroyable
    void Destroy() override;

    const RedisService* redis_service;
    // If user starts a transaction, transaction_handler indicates the
    // handler pointer that runs the transaction command.
    std::unique_ptr<RedisCommandHandler> transaction_handler;
    // >0 if command handler is run in batched mode.
    int batched_size;

    RedisCommandParser parser;
    butil::Arena arena;
};

int ConsumeCommand(RedisConnContext* ctx,
                   const std::vector<butil::StringPiece>& args,
                   bool flush_batched,
                   butil::IOBufAppender* appender) {
    RedisReply output(&ctx->arena);
    RedisCommandHandlerResult result = REDIS_CMD_HANDLED;
    if (ctx->transaction_handler) {
        result = ctx->transaction_handler->Run(args, &output, flush_batched);
        if (result == REDIS_CMD_HANDLED) {
            ctx->transaction_handler.reset(NULL);
        } else if (result == REDIS_CMD_BATCHED) {
            LOG(ERROR) << "BATCHED should not be returned by a transaction handler.";
            return -1;
        }
    } else {
        RedisCommandHandler* ch = ctx->redis_service->FindCommandHandler(args[0]);
        if (!ch) {
            char buf[64];
            snprintf(buf, sizeof(buf), "ERR unknown command `%s`", args[0].as_string().c_str());
            output.SetError(buf);
        } else {
            result = ch->Run(args, &output, flush_batched);
            if (result == REDIS_CMD_CONTINUE) {
                if (ctx->batched_size != 0) {
                    LOG(ERROR) << "CONTINUE should not be returned in a batched process.";
                    return -1;
                }
                ctx->transaction_handler.reset(ch->NewTransactionHandler());
            } else if (result == REDIS_CMD_BATCHED) {
                ctx->batched_size++;
            }
        }
    }
    if (result == REDIS_CMD_HANDLED) {
        if (ctx->batched_size) {
            if ((int)output.size() != (ctx->batched_size + 1)) {
                LOG(ERROR) << "reply array size can't be matched with batched size, "
                    << " expected=" << ctx->batched_size + 1 << " actual=" << output.size();
                return -1;
            }
            for (int i = 0; i < (int)output.size(); ++i) {
                output[i].SerializeTo(appender);
            }
            ctx->batched_size = 0;
        } else {
            output.SerializeTo(appender);
        }
    } else if (result == REDIS_CMD_CONTINUE) {
        output.SerializeTo(appender);
    } else if (result == REDIS_CMD_BATCHED) {
        // just do nothing and wait handler to return OK.
    } else {
        LOG(ERROR) << "unknown status=" << result;
        return -1;
    }
    return 0;
}

// ========== impl of RedisConnContext ==========

void RedisConnContext::Destroy() {
    delete this;
}

// ========== impl of RedisConnContext ==========

ParseResult ParseRedisMessage(butil::IOBuf* source, Socket* socket,
                              bool read_eof, const void* arg) {
    if (read_eof || source->empty()) {
        return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
    }
    const Server* server = static_cast<const Server*>(arg);
    if (server) {
        const RedisService* const rs = server->options().redis_service;
        if (!rs) {
            return MakeParseError(PARSE_ERROR_TRY_OTHERS);
        }
        RedisConnContext* ctx = static_cast<RedisConnContext*>(socket->parsing_context());
        if (ctx == NULL) {
            ctx = new RedisConnContext(rs);
            socket->reset_parsing_context(ctx);
        }
        std::vector<butil::StringPiece> current_args;
        butil::IOBufAppender appender;
        ParseError err = PARSE_OK;

        err = ctx->parser.Consume(*source, &current_args, &ctx->arena);
        if (err != PARSE_OK) {
            return MakeParseError(err);
        }
        while (true) {
            std::vector<butil::StringPiece> next_args;
            err = ctx->parser.Consume(*source, &next_args, &ctx->arena);
            if (err != PARSE_OK) {
                break;
            }
            if (ConsumeCommand(ctx, current_args, false, &appender) != 0) {
                return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
            }
            current_args.swap(next_args);
        }
        if (ConsumeCommand(ctx, current_args,
                    true /*must be the last message*/, &appender) != 0) {
            return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
        }
        butil::IOBuf sendbuf;
        appender.move_to(sendbuf);
        CHECK(!sendbuf.empty());
        Socket::WriteOptions wopt;
        wopt.ignore_eovercrowded = true;
        LOG_IF(WARNING, socket->Write(&sendbuf, &wopt) != 0)
            << "Fail to send redis reply";
        ctx->arena.clear();
        return MakeParseError(err);
    } else {
        // NOTE(gejun): PopPipelinedInfo() is actually more contended than what
        // I thought before. The Socket._pipeline_q is a SPSC queue pushed before
        // sending and popped when response comes back, being protected by a
        // mutex. Previously the mutex is shared with Socket._id_wait_list. When
        // 200 bthreads access one redis-server, ~1.5s in total is spent on
        // contention in 10-second duration. If the mutex is separated, the time
        // drops to ~0.25s. I further replaced PeekPipelinedInfo() with
        // GivebackPipelinedInfo() to lock only once(when receiving response)
        // in most cases, and the time decreases to ~0.14s.
        PipelinedInfo pi;
        if (!socket->PopPipelinedInfo(&pi)) {
            LOG(WARNING) << "No corresponding PipelinedInfo in socket";
            return MakeParseError(PARSE_ERROR_TRY_OTHERS);
        }

        do {
            InputResponse* msg = static_cast<InputResponse*>(socket->parsing_context());
            if (msg == NULL) {
                msg = new InputResponse;
                socket->reset_parsing_context(msg);
            }

            const int consume_count = (pi.with_auth ? 1 : pi.count);

            ParseError err = msg->response.ConsumePartialIOBuf(*source, consume_count);
            if (err != PARSE_OK) {
                socket->GivebackPipelinedInfo(pi);
                return MakeParseError(err);
            }

            if (pi.with_auth) {
                if (msg->response.reply_size() != 1 ||
                    !(msg->response.reply(0).type() == brpc::REDIS_REPLY_STATUS &&
                      msg->response.reply(0).data().compare("OK") == 0)) {
                    LOG(ERROR) << "Redis Auth failed: " << msg->response;
                    return MakeParseError(PARSE_ERROR_NO_RESOURCE,
                                          "Fail to authenticate with Redis");
                }

                DestroyingPtr<InputResponse> auth_msg(
                     static_cast<InputResponse*>(socket->release_parsing_context()));
                pi.with_auth = false;
                continue;
            }

            CHECK_EQ((uint32_t)msg->response.reply_size(), pi.count);
            msg->id_wait = pi.id_wait;
            socket->release_parsing_context();
            return MakeMessage(msg);
        } while(true);
    }

    return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
}

void ProcessRedisResponse(InputMessageBase* msg_base) {
    const int64_t start_parse_us = butil::cpuwide_time_us();
    DestroyingPtr<InputResponse> msg(static_cast<InputResponse*>(msg_base));

    const bthread_id_t cid = msg->id_wait;
    Controller* cntl = NULL;
    const int rc = bthread_id_lock(cid, (void**)&cntl);
    if (rc != 0) {
        LOG_IF(ERROR, rc != EINVAL && rc != EPERM)
            << "Fail to lock correlation_id=" << cid << ": " << berror(rc);
        return;
    }

    ControllerPrivateAccessor accessor(cntl);
    Span* span = accessor.span();
    if (span) {
        span->set_base_real_us(msg->base_real_us());
        span->set_received_us(msg->received_us());
        span->set_response_size(msg->response.ByteSize());
        span->set_start_parse_us(start_parse_us);
    }
    const int saved_error = cntl->ErrorCode();
    if (cntl->response() != NULL) {
        if (cntl->response()->GetDescriptor() != RedisResponse::descriptor()) {
            cntl->SetFailed(ERESPONSE, "Must be RedisResponse");
        } else {
            // We work around ParseFrom of pb which is just a placeholder.
            if (msg->response.reply_size() != (int)accessor.pipelined_count()) {
                cntl->SetFailed(ERESPONSE, "pipelined_count=%d of response does "
                                      "not equal request's=%d",
                                      msg->response.reply_size(), accessor.pipelined_count());
            }
            ((RedisResponse*)cntl->response())->Swap(&msg->response);
            if (FLAGS_redis_verbose) {
                LOG(INFO) << "\n[REDIS RESPONSE] "
                          << *((RedisResponse*)cntl->response());
            }
        }
    } // silently ignore the response.

    // Unlocks correlation_id inside. Revert controller's
    // error code if it version check of `cid' fails
    msg.reset();  // optional, just release resourse ASAP
    accessor.OnResponse(cid, saved_error);
}

void ProcessRedisRequest(InputMessageBase* msg_base) { }

void SerializeRedisRequest(butil::IOBuf* buf,
                           Controller* cntl,
                           const google::protobuf::Message* request) {
    if (request == NULL) {
        return cntl->SetFailed(EREQUEST, "request is NULL");
    }
    if (request->GetDescriptor() != RedisRequest::descriptor()) {
        return cntl->SetFailed(EREQUEST, "The request is not a RedisRequest");
    }
    const RedisRequest* rr = (const RedisRequest*)request;
    // We work around SerializeTo of pb which is just a placeholder.
    if (!rr->SerializeTo(buf)) {
        return cntl->SetFailed(EREQUEST, "Fail to serialize RedisRequest");
    }
    ControllerPrivateAccessor(cntl).set_pipelined_count(rr->command_size());
    if (FLAGS_redis_verbose) {
        LOG(INFO) << "\n[REDIS REQUEST] " << *rr;
    }
}

void PackRedisRequest(butil::IOBuf* buf,
                      SocketMessage**,
                      uint64_t /*correlation_id*/,
                      const google::protobuf::MethodDescriptor*,
                      Controller* cntl,
                      const butil::IOBuf& request,
                      const Authenticator* auth) {
    if (auth) {
        std::string auth_str;
        if (auth->GenerateCredential(&auth_str) != 0) {
            return cntl->SetFailed(EREQUEST, "Fail to generate credential");
        }
        buf->append(auth_str);
        ControllerPrivateAccessor(cntl).add_with_auth();
    } else {
        ControllerPrivateAccessor(cntl).clear_with_auth();
    }

    buf->append(request);
}

const std::string& GetRedisMethodName(
    const google::protobuf::MethodDescriptor*,
    const Controller*) {
    const static std::string REDIS_SERVER_STR = "redis-server";
    return REDIS_SERVER_STR;
}

}  // namespace policy
} // namespace brpc


void join(const rigid_pressure_force_reducer &other) {
    myTotalForce += other.myTotalForce;
    myTotalTorque += other.myTotalTorque;
  }

#include "FLIP_vdb.h"
#include <omp.h>
#include <zeno/MeshObject.h>
#include <zeno/NumericObject.h>
#include <zeno/PrimitiveObject.h>
#include <zeno/VDBGrid.h>
#include <zeno/zeno.h>

namespace zeno {

struct rigid_body_surface_voxel_mask_reducer {

  rigid_body_surface_voxel_mask_reducer(
      const std::vector<zeno::vec3f> &inPosArray,
      openvdb::FloatGrid::Ptr inLiquidSDF)
      : myPosArray(inPosArray), myLiquidSDF(inLiquidSDF) {
    myMask = openvdb::BoolGrid::create(false);
  }

  rigid_body_surface_voxel_mask_reducer(
      const rigid_body_surface_voxel_mask_reducer &other, tbb::split)
      : myPosArray(other.myPosArray), myLiquidSDF(other.myLiquidSDF) {
    myMask = openvdb::BoolGrid::create(false);
  }

  void operator()(const tbb::blocked_range<size_t> &r) {
    using namespace openvdb::tools::local_util;
    // Const accessors
    auto LiquidSDFAccessor(myLiquidSDF->getConstUnsafeAccessor());
    auto MaskAccessor(myMask->getAccessor());

    // pos is a refined sample of object face,
    // so here simply rasterize it to a temple vdb field mask
    // for p in pos, ijk = worldToIndex(p), mask(ijk)=1
    for (size_t i = r.begin(); i != r.end(); ++i) {
      const auto &p = myPosArray[i];
      // 1 find the index position of this position
      openvdb::Vec3f vdbwpos{p[0], p[1], p[2]};
      openvdb::Vec3f vdbipos = myLiquidSDF->worldToIndex(vdbwpos);

      // note phi is defined at the cell center
      // therefore to find the right sdf voxel this point belongs to,
      // a 0.5f shift is required.
      const openvdb::Coord gcoord{floorVec3(vdbipos + openvdb::Vec3f(0.5f))};
      if (LiquidSDFAccessor.getValue(gcoord) < 0) {
        MaskAccessor.setValueOn(gcoord);
      }
    } // End loop all points
  }

  void join(const rigid_body_surface_voxel_mask_reducer &other) {
    myMask->topologyUnion(*other.myMask);
  }

  const std::vector<zeno::vec3f> &myPosArray;

  openvdb::BoolGrid::Ptr myMask;
  openvdb::FloatGrid::Ptr myLiquidSDF;
};

struct rigid_pressure_force_reducer {
  rigid_pressure_force_reducer(
      const std::vector<openvdb::BoolTree::LeafNodeType *> &inMaskLeaves,
      const openvdb::Vec3f &inMassCenter, openvdb::FloatGrid::Ptr inPressure,
      openvdb::Vec3fGrid::Ptr inFaceWeights, float indt)
      : myMaskLeaves(inMaskLeaves), myMassCenter(inMassCenter),
        myPressure(inPressure), myFaceWeights(inFaceWeights), dt(indt) {
    myTotalForce = openvdb::Vec3f{0.f};
    myTotalTorque = openvdb::Vec3f{0.f};
  }

  rigid_pressure_force_reducer(const rigid_pressure_force_reducer &other,
                               tbb::split)
      : myMaskLeaves(other.myMaskLeaves), myMassCenter(other.myMassCenter),
        myPressure(other.myPressure), myFaceWeights(other.myFaceWeights),
        dt(other.dt) {
    myTotalForce = openvdb::Vec3f{0.f};
    myTotalTorque = openvdb::Vec3f{0.f};
  }

  void operator()(const tbb::blocked_range<size_t> &r) {
    using namespace openvdb::tools::local_util;
    // Const accessors
    auto PressureAccessor(myPressure->getConstUnsafeAccessor());
    auto FaceWeightsAccessor(myFaceWeights->getConstUnsafeAccessor());

    double dx = myPressure->voxelSize()[0];
    double dx2 = dx * dx;
    for (size_t i = r.begin(); i != r.end(); ++i) {
      const auto &leaf = *myMaskLeaves[i];

      // for all active liquid masks
      for (auto iter = leaf.beginValueOn(); iter; ++iter) {
        const auto gcoord = iter.getCoord();
        openvdb::Vec3f voxelCenter = myPressure->indexToWorld(gcoord);
        // mathematics: the pressure force a boundary element receives
        // equals to  the pressure force it sends to fluid
        //             ____________
        //   note how this is a better approx to p*n*dA;
        openvdb::Vec3f ForceToFluid{0.f};
        openvdb::Vec3f thisWeight = FaceWeightsAccessor.getValue(gcoord);
        ForceToFluid.x() =
            FaceWeightsAccessor.getValue(gcoord.offsetBy(1, 0, 0))[0] -
            thisWeight[0];
        ForceToFluid.y() =
            FaceWeightsAccessor.getValue(gcoord.offsetBy(0, 1, 0))[1] -
            thisWeight[1];
        ForceToFluid.z() =
            FaceWeightsAccessor.getValue(gcoord.offsetBy(0, 0, 1))[2] -
            thisWeight[2];
        openvdb::Vec3f ForceFromFluid =
            -ForceToFluid * dx2 * PressureAccessor.getValue(gcoord);
        // as a result, we only cumulate for each boundary
        //  cell(we marked out in step1)
        //   for each marked boundary cell,
        myTotalForce += dt * ForceFromFluid;
        myTotalTorque +=
            dt * (voxelCenter - myMassCenter).cross(ForceFromFluid);
      } // end for all active voxels
    }   // end for all leaves
  }     // End operator()

  const std::vector<openvdb::BoolTree::LeafNodeType *> &myMaskLeaves;
  const openvdb::Vec3f &myMassCenter;
  const float dt;

  openvdb::FloatGrid::Ptr myPressure;
  openvdb::Vec3fGrid::Ptr myFaceWeights;
  openvdb::Vec3f myTotalForce;
  openvdb::Vec3f myTotalTorque;
};
void samplePressureForce(float dt, std::vector<zeno::vec3f> &pos,
                         openvdb::FloatGrid::Ptr &pressure,
                         openvdb::Vec3fGrid::Ptr &faceWeights,
                         openvdb::FloatGrid::Ptr &liquid_sdf,
                         zeno::vec3f &massCenter, zeno::vec3f &totalForce,
                         zeno::vec3f &totalTorc) {
  // pos is a refined sample of object face,
  // so here simply rasterize it to a temple vdb field mask
  // for p in pos, ijk = worldToIndex(p), mask(ijk)=1
  rigid_body_surface_voxel_mask_reducer mask_reducer(pos, liquid_sdf);

  // The grain size here prevent tbb generate too much threads because creating
  // a tree has overhead. Tune this parameter to get optimal performance
  tbb::parallel_reduce(
      tbb::blocked_range<size_t>(0, pos.size(), /*grain size*/ 1),
      mask_reducer);

  std::vector<openvdb::BoolTree::LeafNodeType *> mask_leaves;
  mask_leaves.reserve(mask_reducer.myMask->tree().leafCount());
  mask_reducer.myMask->tree().getNodes(mask_leaves);

  // mathematics: the pressure force a boundary element receives
  // equals to  the pressure force it sends to fluid
  //             ____________
  //   note how this is a better approx to p*n*dA;
  //  as a result, we only cumulate for each boundary
  //  cell(we marked out in step1)
  //   for each marked boundary cell,
  openvdb::Vec3f masscenter{massCenter[0], massCenter[1], massCenter[2]};
  rigid_pressure_force_reducer ForceReducer(mask_leaves, masscenter, pressure,
                                            faceWeights, dt);

  tbb::parallel_reduce(
      tbb::blocked_range<size_t>(0, mask_leaves.size(), /*grain size*/ 1),
      ForceReducer);

  for (int i = 0; i < 3; i++) {
    totalForce[i] = ForceReducer.myTotalForce[i];
    totalTorc[i] = ForceReducer.myTotalTorque[i];
  }
}
struct RigidGetPressureForce : zeno::INode {
  virtual void apply() override {
    auto dt = get_input("dt")->as<zeno::NumericObject>()->get<float>();
    auto massCenter =
        get_input("MassCenter")->as<zeno::NumericObject>()->get<zeno::vec3f>();
    auto rigid = get_input("Rigid")->as<zeno::PrimitiveObject>();
    auto Pressure = get_input("Pressure")->as<zeno::VDBFloatGrid>();
    auto CellFWeight = get_input("CellFWeight")->as<zeno::VDBFloat3Grid>();
    auto LiquidSDF = get_input("LiquidSDF")->as<zeno::VDBFloatGrid>();
    auto TotalForceImpulse = zeno::IObject::make<zeno::NumericObject>();
    auto TotalTorcImpulse = zeno::IObject::make<zeno::NumericObject>();
    std::vector<zeno::vec3f> pos;
    pos.resize(rigid->attr<zeno::vec3f>("pos").size());
#pragma omp parallel for
    for (int i = 0; i < rigid->attr<zeno::vec3f>("pos").size(); i++) {
      pos[i] = rigid->attr<zeno::vec3f>("pos")[i];
    }
    zeno::vec3f totalForce;
    zeno::vec3f totalTorc;
    samplePressureForce(dt, pos, Pressure->m_grid, CellFWeight->m_grid,
                        LiquidSDF->m_grid, massCenter, totalForce, totalTorc);
    TotalForceImpulse->set<zeno::vec3f>(totalForce);
    TotalTorcImpulse->set<zeno::vec3f>(totalTorc);
    set_output("TotalForceImpulse", TotalForceImpulse);
    set_output("TotalTorcImpulse", TotalTorcImpulse);
  }
};
static int defRigidGetPressureForce = zeno::defNodeClass<RigidGetPressureForce>(
    "RigidGetPressureForce", {/* inputs: */ {
                                  "dt",
                                  "MassCenter",
                                  "Rigid",
                                  "Pressure",
                                  "CellFWeight",
                                  "LiquidSDF",
                              },
                              /* outputs: */
                              {
                                  "TotalForceImpulse",
                                  "TotalTorcImpulse",
                              },
                              /* params: */
                              {
                                  {"float", "dx", "0.0"},
                              },

                              /* category: */
                              {
                                  "FLIPSolver",
                              }});
} // namespace zeno


static void rtThreadKeyDestruct(void *pvValue)
{
    /*
     * Deal with alien threads.
     */
    PRTTHREADINT pThread = (PRTTHREADINT)pvValue;
    if (pThread->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
    {
        pthread_setspecific(g_SelfKey, pThread);
        rtThreadTerminate(pThread, 0);
        pthread_setspecific(g_SelfKey, NULL);
    }
}

/* $Id: thread-posix.cpp $ */
/** @file
 * IPRT - Threads, POSIX.
 */

/*
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 *
 * The contents of this file may alternatively be used under the terms
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 * VirtualBox OSE distribution, in which case the provisions of the
 *
 * You may elect to license modified versions of this file under the
 */

/*********************************************************************************************************************************
*   Header Files                                                                                *
*********************************************************************************************************************************/
#define LOG_GROUP RTLOGGROUP_THREAD
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#if defined(RT_OS_LINUX)
# include <unistd.h>
# include <sys/syscall.h>
#endif
#if defined(RT_OS_SOLARIS)
# include <sched.h>
# include <sys/resource.h>
#endif
#if defined(RT_OS_DARWIN)
# include <mach/thread_act.h>
# include <mach/thread_info.h>
# include <mach/host_info.h>
# include <mach/mach_init.h>
# include <mach/mach_host.h>
#endif
#if defined(RT_OS_DARWIN) /*|| defined(RT_OS_FREEBSD) - later */ \
 || (defined(RT_OS_LINUX) && !defined(IN_RT_STATIC) /* static + dlsym = trouble */) \
 || defined(IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP)
# define IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
# include <dlfcn.h>
#endif
#if defined(RT_OS_HAIKU)
# include <OS.h>
#endif

#include <iprt/thread.h>
#include <iprt/log.h>
#include <iprt/assert.h>
#include <iprt/asm.h>
#include <iprt/err.h>
#include <iprt/initterm.h>
#include <iprt/string.h>
#include "internal/thread.h"

/*********************************************************************************************************************************
*   Defined Constants And Macros                                                                                *
*********************************************************************************************************************************/
#ifndef IN_GUEST
/** Includes RTThreadPoke. */
# define RTTHREAD_POSIX_WITH_POKE
#endif

/*********************************************************************************************************************************
*   Global Variables                                                                                *
*********************************************************************************************************************************/
/** The pthread key in which we store the pointer to our own PRTTHREAD structure. */
static pthread_key_t    g_SelfKey;
#ifdef RTTHREAD_POSIX_WITH_POKE
/** The signal we use for poking threads.
 * This is set to -1 if no available signal was found. */
static int              g_iSigPokeThread = -1;
#endif

#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
# if defined(RT_OS_DARWIN)
/**
 * The Mac OS X (10.6 and later) variant of pthread_setname_np.
 *
 * @returns errno.h
 * @param   pszName         The new thread name.
 */
typedef int (*PFNPTHREADSETNAME)(const char *pszName);
# else
/**
 * The variant of pthread_setname_np most other unix-like systems implement.
 *
 * @returns errno.h
 * @param   hThread         The thread.
 * @param   pszName         The new thread name.
 */
typedef int (*PFNPTHREADSETNAME)(pthread_t hThread, const char *pszName);
# endif

/** Pointer to pthread_setname_np if found. */
static PFNPTHREADSETNAME g_pfnThreadSetName = NULL;
#endif /* IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP */

/*********************************************************************************************************************************
*   Internal Functions                                                                                *
*********************************************************************************************************************************/
static void *rtThreadNativeMain(void *pvArgs);
static void rtThreadKeyDestruct(void *pvValue);
#ifdef RTTHREAD_POSIX_WITH_POKE
static void rtThreadPosixPokeSignal(int iSignal);
#endif

#ifdef RTTHREAD_POSIX_WITH_POKE
/**
 * Try register the dummy signal handler for RTThreadPoke.
 */
static void rtThreadPosixSelectPokeSignal(void)
{
    /*
     * Note! Avoid SIGRTMIN thru SIGRTMIN+2 because of LinuxThreads.
     */
    static const int s_aiSigCandidates[] =
    {
# ifdef SIGRTMAX
        SIGRTMAX-3,
        SIGRTMAX-2,
        SIGRTMAX-1,
# endif
# ifndef RT_OS_SOLARIS
        SIGUSR2,
# endif
        SIGWINCH
    };

    g_iSigPokeThread = -1;
    if (!RTR3InitIsUnobtrusive())
    {
        for (unsigned iSig = 0; iSig < RT_ELEMENTS(s_aiSigCandidates); iSig++)
        {
            struct sigaction SigActOld;
            if (!sigaction(s_aiSigCandidates[iSig], NULL, &SigActOld))
            {
                if (   SigActOld.sa_handler == SIG_DFL
                    || SigActOld.sa_handler == rtThreadPosixPokeSignal)
                {
                    struct sigaction SigAct;
                    RT_ZERO(SigAct);
                    SigAct.sa_handler = rtThreadPosixPokeSignal;
                    SigAct.sa_flags   = 0;
                    sigfillset(&SigAct.sa_mask);

                    /* ASSUMES no sigaction race... (lazy bird) */
                    if (!sigaction(s_aiSigCandidates[iSig], &SigAct, NULL))
                    {
                        g_iSigPokeThread = s_aiSigCandidates[iSig];
                        break;
                    }
                    AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
                }
            }
            else
                AssertMsgFailed(("rc=%Rrc errno=%d\n", RTErrConvertFromErrno(errno), errno));
        }
    }
}
#endif /* RTTHREAD_POSIX_WITH_POKE */

DECLHIDDEN(int) rtThreadNativeInit(void)
{
    /*
     * Allocate the TLS (key in posix terms) where we store the pointer to
     * a threads RTTHREADINT structure.
     */
    int rc = pthread_key_create(&g_SelfKey, rtThreadKeyDestruct);
    if (rc)
        return VERR_NO_TLS_FOR_SELF;

#ifdef RTTHREAD_POSIX_WITH_POKE
    rtThreadPosixSelectPokeSignal();
#endif

#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
    if (RT_SUCCESS(rc))
        g_pfnThreadSetName = (PFNPTHREADSETNAME)(uintptr_t)dlsym(RTLD_DEFAULT, "pthread_setname_np");
#endif
    return rc;
}

static void rtThreadPosixBlockSignals(void)
{
    /*
     * Block SIGALRM - required for timer-posix.cpp.
     * This is done to limit harm done by OSes which doesn't do special SIGALRM scheduling.
     * It will not help much if someone creates threads directly using pthread_create. :/
     */
    if (!RTR3InitIsUnobtrusive())
    {
        sigset_t SigSet;
        sigemptyset(&SigSet);
        sigaddset(&SigSet, SIGALRM);
        sigprocmask(SIG_BLOCK, &SigSet, NULL);
    }
#ifdef RTTHREAD_POSIX_WITH_POKE
    if (g_iSigPokeThread != -1)
        siginterrupt(g_iSigPokeThread, 1);
#endif
}

DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void)
{
#ifdef RTTHREAD_POSIX_WITH_POKE
    Assert(!RTR3InitIsUnobtrusive());
    rtThreadPosixSelectPokeSignal();
#endif
    rtThreadPosixBlockSignals();
}

/**
 * Destructor called when a thread terminates.
 * @param   pvValue     The key value. PRTTHREAD in our case.
 */

#ifdef RTTHREAD_POSIX_WITH_POKE
/**
 * Dummy signal handler for the poke signal.
 *
 * @param   iSignal     The signal number.
 */
static void rtThreadPosixPokeSignal(int iSignal)
{
    Assert(iSignal == g_iSigPokeThread);
    NOREF(iSignal);
}
#endif

/**
 * Adopts a thread, this is called immediately after allocating the
 * thread structure.
 *
 * @param   pThread     Pointer to the thread structure.
 */
DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
{
    rtThreadPosixBlockSignals();

    int rc = pthread_setspecific(g_SelfKey, pThread);
    if (!rc)
        return VINF_SUCCESS;
    return VERR_FAILED_TO_SET_SELF_TLS;
}

DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
{
    if (pThread == (PRTTHREADINT)pthread_getspecific(g_SelfKey))
        pthread_setspecific(g_SelfKey, NULL);
}

/**
 * Wrapper which unpacks the params and calls thread function.
 */
static void *rtThreadNativeMain(void *pvArgs)
{
    PRTTHREADINT  pThread = (PRTTHREADINT)pvArgs;
    pthread_t     Self    = pthread_self();
    Assert((uintptr_t)Self != NIL_RTNATIVETHREAD);
    Assert(Self == (pthread_t)(RTNATIVETHREAD)Self);

#if defined(RT_OS_LINUX)
    /*
     * Set the TID.
     */
    pThread->tid = syscall(__NR_gettid);
    ASMMemoryFence();
#endif

    rtThreadPosixBlockSignals();

    /*
     * Set the TLS entry and, if possible, the thread name.
     */
    int rc = pthread_setspecific(g_SelfKey, pThread);
    AssertReleaseMsg(!rc, ("failed to set self TLS. rc=%d thread '%s'\n", rc, pThread->szName));

#ifdef IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP
    if (g_pfnThreadSetName)
# ifdef RT_OS_DARWIN
        g_pfnThreadSetName(pThread->szName);
# else
        g_pfnThreadSetName(Self, pThread->szName);
# endif
#endif

    /*
     * Call common main.
     */
    rc = rtThreadMain(pThread, (uintptr_t)Self, &pThread->szName[0]);

    pthread_setspecific(g_SelfKey, NULL);
    pthread_exit((void *)(intptr_t)rc);
    return (void *)(intptr_t)rc;
}

DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
{
    /*
     * Set the default stack size.
     */
    if (!pThread->cbStack)
        pThread->cbStack = 512*1024;

#ifdef RT_OS_LINUX
    pThread->tid = -1;
#endif

    /*
     * Setup thread attributes.
     */
    pthread_attr_t  ThreadAttr;
    int rc = pthread_attr_init(&ThreadAttr);
    if (!rc)
    {
        rc = pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_DETACHED);
        if (!rc)
        {
            rc = pthread_attr_setstacksize(&ThreadAttr, pThread->cbStack);
            if (!rc)
            {
                /*
                 * Create the thread.
                 */
                pthread_t ThreadId;
                rc = pthread_create(&ThreadId, &ThreadAttr, rtThreadNativeMain, pThread);
                if (!rc)
                {
                    pthread_attr_destroy(&ThreadAttr);
                    *pNativeThread = (uintptr_t)ThreadId;
                    return VINF_SUCCESS;
                }
            }
        }
        pthread_attr_destroy(&ThreadAttr);
    }
    return RTErrConvertFromErrno(rc);
}

RTDECL(RTTHREAD) RTThreadSelf(void)
{
    PRTTHREADINT pThread = (PRTTHREADINT)pthread_getspecific(g_SelfKey);
    /** @todo import alien threads? */
    return pThread;
}

#ifdef RTTHREAD_POSIX_WITH_POKE
RTDECL(int) RTThreadPoke(RTTHREAD hThread)
{
    AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
    PRTTHREADINT pThread = rtThreadGet(hThread);
    AssertReturn(pThread, VERR_INVALID_HANDLE);

    int rc;
    if (g_iSigPokeThread != -1)
    {
        rc = pthread_kill((pthread_t)(uintptr_t)pThread->Core.Key, g_iSigPokeThread);
        rc = RTErrConvertFromErrno(rc);
    }
    else
        rc = VERR_NOT_SUPPORTED;

    rtThreadRelease(pThread);
    return rc;
}
#endif

/** @todo move this into platform specific files. */
RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime)
{
#if defined(RT_OS_SOLARIS)
    struct rusage ts;
    int rc = getrusage(RUSAGE_LWP, &ts);
    if (rc)
        return RTErrConvertFromErrno(rc);

    *pKernelTime = ts.ru_stime.tv_sec * 1000 + ts.ru_stime.tv_usec / 1000;
    *pUserTime   = ts.ru_utime.tv_sec * 1000 + ts.ru_utime.tv_usec / 1000;
    return VINF_SUCCESS;

#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
    /* on Linux, getrusage(RUSAGE_THREAD, ...) is available since 2.6.26 */
    struct timespec ts;
    int rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
    if (rc)
        return RTErrConvertFromErrno(rc);

    *pKernelTime = 0;
    *pUserTime = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
    return VINF_SUCCESS;

#elif defined(RT_OS_DARWIN)
    thread_basic_info       ThreadInfo;
    mach_msg_type_number_t  Count = THREAD_BASIC_INFO_COUNT;
    kern_return_t krc = thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&ThreadInfo, &Count);
    AssertReturn(krc == KERN_SUCCESS, RTErrConvertFromDarwinKern(krc));

    *pKernelTime = ThreadInfo.system_time.seconds * 1000 + ThreadInfo.system_time.microseconds / 1000;
    *pUserTime   = ThreadInfo.user_time.seconds   * 1000 + ThreadInfo.user_time.microseconds   / 1000;

    return VINF_SUCCESS;
#elif defined(RT_OS_HAIKU)
    thread_info       ThreadInfo;
    status_t status = get_thread_info(find_thread(NULL), &ThreadInfo);
    AssertReturn(status == B_OK, RTErrConvertFromErrno(status));

    *pKernelTime = ThreadInfo.kernel_time / 1000;
    *pUserTime   = ThreadInfo.user_time / 1000;

    return VINF_SUCCESS;
#else
    return VERR_NOT_IMPLEMENTED;
#endif
}


void QwtSimpleCompassRose::setWidth(double width)
{
    d_width = width;
    if (d_width < 0.03)
        d_width = 0.03;

    if (d_width > 0.4)
        d_width = 0.4;
}

/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 *
 *****************************************************************************/

#include <math.h>
#include <qpainter.h>
#include "qwt_math.h"
#include "qwt_painter.h"
#include "qwt_compass_rose.h"

static QPoint cutPoint(QPoint p11, QPoint p12, QPoint p21, QPoint p22)
{
    double dx1 = p12.x() - p11.x();
    double dy1 = p12.y() - p11.y();
    double dx2 = p22.x() - p21.x();
    double dy2 = p22.y() - p21.y();

    if ( dx1 == 0.0 && dx2 == 0.0 )
        return QPoint();

    if ( dx1 == 0.0 ) {
        const double m = dy2 / dx2;
        const double t = p21.y() - m * p21.x();
        return QPoint(p11.x(), qRound(m * p11.x() + t));
    }

    if ( dx2 == 0 ) {
        const double m = dy1 / dx1;
        const double t = p11.y() - m * p11.x();
        return QPoint(p21.x(), qRound(m * p21.x() + t));
    }

    const double m1 = dy1 / dx1;
    const double t1 = p11.y() - m1 * p11.x();

    const double m2 = dy2 / dx2;
    const double t2 = p21.y() - m2 * p21.x();

    if ( m1 == m2 )
        return QPoint();

    const double x = ( t2 - t1 ) / ( m1 - m2 );
    const double y = t1 + m1 * x;

    return QPoint(qRound(x), qRound(y));
}

/*!
   Constructor

   \param numThorns Number of thorns
   \param numThornLevels Number of thorn levels
*/
QwtSimpleCompassRose::QwtSimpleCompassRose(int numThorns, int numThornLevels):
    d_width(0.2),
    d_numThorns(numThorns),
    d_numThornLevels(numThornLevels),
    d_shrinkFactor(0.9)
{
    const QColor dark(128,128,255);
    const QColor light(192,255,255);

    QPalette palette;
    for ( int i = 0; i < QPalette::NColorGroups; i++ ) {
#if QT_VERSION < 0x040000
        palette.setColor((QPalette::ColorGroup)i,
                         QColorGroup::Dark, dark);
        palette.setColor((QPalette::ColorGroup)i,
                         QColorGroup::Light, light);
#else
        palette.setColor((QPalette::ColorGroup)i,
                         QPalette::Dark, dark);
        palette.setColor((QPalette::ColorGroup)i,
                         QPalette::Light, light);
#endif
    }

    setPalette(palette);
}

/*!
   Draw the rose

   \param painter Painter
   \param center Center point
   \param radius Radius of the rose
   \param north Position
   \param cg Color group
*/
void QwtSimpleCompassRose::draw(QPainter *painter, const QPoint &center,
                                int radius, double north, QPalette::ColorGroup cg) const
{
#if QT_VERSION < 0x040000
    QColorGroup colorGroup;
    switch(cg) {
    case QPalette::Disabled:
        colorGroup = palette().disabled();
    case QPalette::Inactive:
        colorGroup = palette().inactive();
    default:
        colorGroup = palette().active();
    }

    drawRose(painter, colorGroup, center, radius, north, d_width,
             d_numThorns, d_numThornLevels, d_shrinkFactor);
#else
    QPalette pal = palette();
    pal.setCurrentColorGroup(cg);
    drawRose(painter, pal, center, radius, north, d_width,
             d_numThorns, d_numThornLevels, d_shrinkFactor);
#endif
}

/*!
   Draw the rose

   \param painter Painter
   \param palette Palette
   \param center Center of the rose
   \param radius Radius of the rose
   \param north Position pointing to north
   \param width Width of the rose
   \param numThorns Number of thorns
   \param numThornLevels Number of thorn levels
   \param shrinkFactor Factor to shrink the thorns with each level
*/
void QwtSimpleCompassRose::drawRose(
    QPainter *painter,
#if QT_VERSION < 0x040000
    const QColorGroup &cg,
#else
    const QPalette &palette,
#endif
    const QPoint &center, int radius, double north, double width,
    int numThorns, int numThornLevels, double shrinkFactor)
{
    if ( numThorns < 4 )
        numThorns = 4;

    if ( numThorns % 4 )
        numThorns += 4 - numThorns % 4;

    if ( numThornLevels <= 0 )
        numThornLevels = numThorns / 4;

    if ( shrinkFactor >= 1.0 )
        shrinkFactor = 1.0;

    if ( shrinkFactor <= 0.5 )
        shrinkFactor = 0.5;

    painter->save();

    painter->setPen(Qt::NoPen);

    for ( int j = 1; j <= numThornLevels; j++ ) {
        double step =  pow(2.0, j) * M_PI / (double)numThorns;
        if ( step > M_PI_2 )
            break;

        double r = radius;
        for ( int k = 0; k < 3; k++ ) {
            if ( j + k < numThornLevels )
                r *= shrinkFactor;
        }

        double leafWidth = r * width;
        if ( 2.0 * M_PI / step > 32 )
            leafWidth = 16;

        const double origin = north / 180.0 * M_PI;
        for ( double angle = origin;
                angle < 2.0 * M_PI + origin; angle += step) {
            const QPoint p = qwtPolar2Pos(center, r, angle);
            QPoint p1 = qwtPolar2Pos(center, leafWidth, angle + M_PI_2);
            QPoint p2 = qwtPolar2Pos(center, leafWidth, angle - M_PI_2);

            QwtPolygon pa(3);
            pa.setPoint(0, center);
            pa.setPoint(1, p);

            QPoint p3 = qwtPolar2Pos(center, r, angle + step / 2.0);
            p1 = cutPoint(center, p3, p1, p);
            pa.setPoint(2, p1);
#if QT_VERSION < 0x040000
            painter->setBrush(cg.brush(QColorGroup::Dark));
#else
            painter->setBrush(palette.brush(QPalette::Dark));
#endif
            painter->drawPolygon(pa);

            QPoint p4 = qwtPolar2Pos(center, r, angle - step / 2.0);
            p2 = cutPoint(center, p4, p2, p);

            pa.setPoint(2, p2);
#if QT_VERSION < 0x040000
            painter->setBrush(cg.brush(QColorGroup::Light));
#else
            painter->setBrush(palette.brush(QPalette::Light));
#endif
            painter->drawPolygon(pa);
        }
    }
    painter->restore();
}

/*!
   Set the width of the rose heads. Lower value make thinner heads.
   The range is limited from 0.03 to 0.4.

   \param width Width
*/

/*!
  Set the number of thorns on one level
  The number is aligned to a multiple of 4, with a minimum of 4

  \param numThorns Number of thorns
  \sa numThorns(), setNumThornLevels()
*/
void QwtSimpleCompassRose::setNumThorns(int numThorns)
{
    if ( numThorns < 4 )
        numThorns = 4;

    if ( numThorns % 4 )
        numThorns += 4 - numThorns % 4;

    d_numThorns = numThorns;
}

/*!
   \return Number of thorns
   \sa setNumThorns(), setNumThornLevels()
*/
int QwtSimpleCompassRose::numThorns() const
{
    return d_numThorns;
}

/*!
  Set the of thorns levels

  \param numThornLevels Number of thorns levels
  \sa setNumThorns(), numThornLevels()
*/
void QwtSimpleCompassRose::setNumThornLevels(int numThornLevels)
{
    d_numThornLevels = numThornLevels;
}

/*!
   \return Number of thorn levels
   \sa setNumThorns(), setNumThornLevels()
*/
int QwtSimpleCompassRose::numThornLevels() const
{
    return d_numThornLevels;
}


cplus/github/wyrover/book-code/Professional C++, 3rd Edition/c16_code/09_RoundRobin/RoundRobinTest.cpp

bool operator==(const Process& rhs)
    {
        return mName == rhs.mName;
    }

#include "RoundRobin.h"
#include <stdexcept>
#include <iostream>
#include <string>
using namespace std;

class Process
{
public:
    // Constructor accepting the name of the process.
    Process(const string& name) : mName(name) {}

    // Implementation of doWorkDuringTimeSlice would let the process
    // perform its work for the duration of a time slice.
    // Actual implementation omitted.
    void doWorkDuringTimeSlice()
    {
        cout << "Process " << mName
             << " performing work during time slice." << endl;
    }

    // Needed for the RoundRobin::remove method to work.

private:
    string mName;
};

// Simple round-robin based process scheduler.
class Scheduler
{
public:
    // Constructor takes a vector of processes.
    Scheduler(const vector<Process>& processes);

    // Selects the next process using a round-robin scheduling
    // algorithm and allows it to perform some work during
    void scheduleTimeSlice();

    // Removes the given process from the list of processes.
    void removeProcess(const Process& process);

private:
    RoundRobin<Process> rr;
};

Scheduler::Scheduler(const vector<Process>& processes)
{
    // Add the processes
    for (auto& process : processes) {
        rr.add(process);
    }

    // If your compiler does not support the above C++11
    // range-based for loop, you need the following instead:
}

void Scheduler::scheduleTimeSlice()
{
    try {
        rr.getNext().doWorkDuringTimeSlice();
    } catch (const out_of_range&) {
        cerr << "No more processes to schedule." << endl;
    }
}

void Scheduler::removeProcess(const Process& process)
{
    rr.remove(process);
}

int main()
{
    vector<Process> processes = { Process("1"), Process("2"), Process("3") };
    // If your compiler does not support the above uniform
    // initialization from C++11, you need the following:
    Scheduler sched(processes);

    for (int i = 0; i < 4; ++i)
        sched.scheduleTimeSlice();

    sched.removeProcess(processes[1]);
    cout << "Removed second process" << endl;

    for (int i = 0; i < 4; ++i)
        sched.scheduleTimeSlice();

    return 0;
}


try {
        rr.getNext().doWorkDuringTimeSlice();
    } catch (const out_of_range&) {
        cerr << "No more processes to schedule." << endl;
    }

#include "RoundRobin.h"
#include <stdexcept>
#include <iostream>
#include <string>
using namespace std;

class Process
{
public:
    // Constructor accepting the name of the process.
    Process(const string& name) : mName(name) {}

    // Implementation of doWorkDuringTimeSlice would let the process
    // perform its work for the duration of a time slice.
    // Actual implementation omitted.
    void doWorkDuringTimeSlice()
    {
        cout << "Process " << mName
             << " performing work during time slice." << endl;
    }

    // Needed for the RoundRobin::remove method to work.
    bool operator==(const Process& rhs)
    {
        return mName == rhs.mName;
    }

private:
    string mName;
};

// Simple round-robin based process scheduler.
class Scheduler
{
public:
    // Constructor takes a vector of processes.
    Scheduler(const vector<Process>& processes);

    // Selects the next process using a round-robin scheduling
    // algorithm and allows it to perform some work during
    void scheduleTimeSlice();

    // Removes the given process from the list of processes.
    void removeProcess(const Process& process);

private:
    RoundRobin<Process> rr;
};

Scheduler::Scheduler(const vector<Process>& processes)
{
    // Add the processes
    for (auto& process : processes) {
        rr.add(process);
    }

    // If your compiler does not support the above C++11
    // range-based for loop, you need the following instead:
}

void Scheduler::scheduleTimeSlice()
{

}

void Scheduler::removeProcess(const Process& process)
{
    rr.remove(process);
}

int main()
{
    vector<Process> processes = { Process("1"), Process("2"), Process("3") };
    // If your compiler does not support the above uniform
    // initialization from C++11, you need the following:
    Scheduler sched(processes);

    for (int i = 0; i < 4; ++i)
        sched.scheduleTimeSlice();

    sched.removeProcess(processes[1]);
    cout << "Removed second process" << endl;

    for (int i = 0; i < 4; ++i)
        sched.scheduleTimeSlice();

    return 0;
}


void SetErrorGlobals(char *szFileName, int *nLineNumber) {
	FN = szFileName;
	LN = nLineNumber;

	return;
}

/*
 * Legal Notice
 *
 * This document and associated source code (the "Work") is a part of a
 * benchmark specification maintained by the TPC.
 *
 * The TPC reserves all right, title, and interest to the Work as provided
 * under U.S. and international laws, including without limitation all patent
 * and trademark rights therein.
 *
 *
 *
 * Contributors:
 * Gradient Systems
 */
#include "config.h"
#include "porting.h"
#include <stdio.h>
#include "error_msg.h"
#include "grammar_support.h"
static int *LN;
static char *FN;

err_msg_t Errors[MAX_ERROR + 2] = {{
                                       EFLG_NO_ARG,
                                       "",
                                   },
                                   {EFLG_STR_ARG, "File '%s' not found"},
                                   {EFLG_NO_ARG, "Line exceeds maximum leng.h"},
                                   {EFLG_STR_ARG, "Memory allocation failed %s"},
                                   {EFLG_STR_ARG, "Syntax Error: \n'%s'"},
                                   {EFLG_NO_ARG, "Invalid/Out-of-range Argument"},
                                   {EFLG_STR_ARG, "'%s' is not a unique name"},
                                   {EFLG_STR_ARG, "'%s' is not a valid name"},
                                   {EFLG_NO_ARG, "Command parse failed"},
                                   {EFLG_NO_ARG, "Invalid tag found"},
                                   {EFLG_STR_ARG, "Read failed on '%s'"},
                                   {EFLG_NO_ARG, "Too Many Templates!"},
                                   {EFLG_NO_ARG, "Each workload definition must be in its own file"},
                                   {EFLG_NO_ARG, "Query Class name must be unique within a workload definition"},
                                   {EFLG_NO_ARG, "Query Template must be unique within a query class"},
                                   {EFLG_STR_ARG | EFLG_SYSTEM, "Open failed on '%s'"},
                                   {EFLG_STR_ARG, "%s  not yet implemented"}, /* QERR_NOT_IMPLEMENTED */
                                   {EFLG_STR_ARG, "string trucated to '%s'"},
                                   {EFLG_NO_ARG, "Non-terminated string"},
                                   {EFLG_STR_ARG, "failed to write to '%s'"},
                                   {EFLG_NO_ARG, "No type vector defined for distribution"},
                                   {EFLG_NO_ARG, "No weight count defined for distribution"},
                                   {EFLG_NO_ARG, "No limits defined for pricing calculations"},
                                   {EFLG_STR_ARG, "Percentage is out of bounds in substitution '%s'"},
                                   {EFLG_STR_ARG, "Name is not a distribution or table name: '%s'"},
                                   {EFLG_NO_ARG, "Cannot evaluate expression"},
                                   {EFLG_STR_ARG, "Substitution'%s' is used before being initialized"}, /* QERR_NO_INIT
                                                                                */
                                   {EFLG_NO_ARG, "RANGE()/LIST()/ULIST() not supported for NORMAL "
                                                 "distributions"},
                                   {EFLG_STR_ARG, "Bad Nesting; '%s' not found"},
                                   {EFLG_STR_ARG, "Include stack overflow when opening '%s'"},
                                   {EFLG_STR_ARG, "Bad function call: '%s'"},
                                   {EFLG_STR_ARG, "Bad Hierarchy Call: '%s'"},
                                   {EFLG_NO_ARG, "Must set types and weights before defining names"},
                                   {EFLG_NO_ARG, "More than 20 arguments in definition"},
                                   {EFLG_NO_ARG, "Argument type mismat.h"},
                                   {EFLG_NO_ARG, "RANGE()/LIST()/ULIST() cannot be used in the "
                                                 "same expression"}, /* QERR_RANGE_LIST
                                                                      */
                                   {EFLG_NO_ARG, "Selected scale factor is NOT valid for result publication"},
                                   {EFLG_STR_ARG, "Parameter setting failed for '%s'"},
                                   {EFLG_STR_ARG, "Table %s is being joined without an explicit rule"},
                                   {EFLG_STR_ARG, "Table %s is not yet fully defined"},
                                   {EFLG_STR_ARG, "Table %s is a child; it is populated during the build of "
                                                  "its parent (e.g., catalog_sales builds catalog returns)"},
                                   {EFLG_NO_ARG, "Command line arguments for dbgen_version exceed 200 "
                                                 "characters; truncated"},
                                   {EFLG_NO_ARG, "A query template list must be supplied using the "
                                                 "INPUT option"},                               /* QERR_NO_QUERYLIST
                                                                                */
                                   {EFLG_NO_ARG, "Invalid query number found in permutation!"}, /* QERR_QUERY_RANGE
                                                                                */
                                   {EFLG_NO_ARG, "RANGE/LIST/ULIST expressions not valid as "
                                                 "function parameters"}, /* QERR_MODIFIED_PARAM
                                                                          */
                                   {EFLG_NO_ARG, "RANGE/LIST/ULIST truncated to available "
                                                 "values"}, /* QERR_MODIFIED_PARAM
                                                             */
                                   {EFLG_NO_ARG, "This scale factor is valid for QUALIFICATION "
                                                 "ONLY"}, /* QERR_QUALIFICATION_SCALE
                                                           */
                                   {EFLG_STR_ARG, "Generating %s requires the '-update' option"}, /* QERR_TABLE_UPDATE
                                                                                */
                                   {0, NULL}};

/*
 * Routine:
 * Purpose:
 * Algorithm:
 * Data Structures:
 *
 * Params:
 * Returns:
 * Called By:
 * Calls:
 * Assumptions:
 * Side Effects:
 * TODO: None
 */
void ProcessErrorCode(int nErrorCode, char *szRoutineName, char *szParam, int nParam) {
	switch (nErrorCode) {
	case QERR_NO_FILE:
		ReportError(QERR_NO_FILE, szParam, 1);
		break;
	case QERR_SYNTAX:
	case QERR_RANGE_ERROR:
	case QERR_NON_UNIQUE:
	case QERR_BAD_NAME:
	case QERR_DEFINE_OVERFLOW:
	case QERR_INVALID_TAG:
	case QERR_READ_FAILED:
	case QERR_NO_MEMORY:
	case QERR_LINE_TOO_LONG:
		ReportError(nErrorCode, szRoutineName, 1);
		break;
	}
	return;
}

/*
 * Routine:
 * Purpose:
 * Algorithm:
 * Data Structures:
 *
 * Params:
 * Returns:
 * Called By:
 * Calls:
 * Assumptions:
 * Side Effects:
 * TODO: None
 */
int ReportError(int nError, char *msg, int bExit) {
	fprintf(stderr, "ERROR?!\n");
	return (nError);
}

/*
 * Routine:
 * Purpose:
 * Algorithm:
 * Data Structures:
 *
 * Params:
 * Returns:
 * Called By:
 * Calls:
 * Assumptions:
 * Side Effects:
 * TODO: None
 */
int ReportErrorNoLine(int nError, char *msg, int bExit) {
	char e_msg[1024];

	if (nError < MAX_ERROR) {
		switch (Errors[-nError].flags & EFLG_ARG_MASK) {
		case EFLG_NO_ARG:
			fprintf(stderr, "%s: %s\n", (bExit) ? "ERROR" : "Warning", Errors[-nError].prompt);
			break;
		case EFLG_STR_ARG:
			sprintf(e_msg, Errors[-nError].prompt, msg);
			fprintf(stderr, "%s: %s\n", (bExit) ? "ERROR" : "Warning", e_msg);
			break;
		}

		if (Errors[-nError].flags & EFLG_SYSTEM)
			perror(msg);
	}

	if (bExit)
		exit(nError);
	else
		return (nError);
}

/*
 * Routine:
 * Purpose:
 * Algorithm:
 * Data Structures:
 *
 * Params:
 * Returns:
 * Called By:
 * Calls:
 * Assumptions:
 * Side Effects:
 * TODO: None
 */


void DriverBase::scheduleRelease(AcquiredImage const& image) noexcept {
    scheduleCallback(image.handler, [image]() {
        image.callback(image.image, image.userData);
    });
}

/*
 *
 */

#include "private/backend/Driver.h"
#include "private/backend/CommandStream.h"

#include "DriverBase.h"

#include <math/half.h>
#include <math/vec2.h>
#include <math/vec3.h>
#include <math/vec4.h>

#include <backend/BufferDescriptor.h>
#include <backend/PixelBufferDescriptor.h>

#include <utils/Systrace.h>

using namespace utils;

namespace filament {

using namespace math;

namespace backend {

DriverBase::DriverBase(Dispatcher* dispatcher) noexcept
        : mDispatcher(dispatcher) {
    if constexpr (UTILS_HAS_THREADING) {
        // This thread services user callbacks
        mServiceThread = std::thread([this]() {
            do {
                auto& serviceThreadCondition = mServiceThreadCondition;
                auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;

                // wait for some callbacks to dispatch
                std::unique_lock<std::mutex> lock(mServiceThreadLock);
                while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
                    serviceThreadCondition.wait(lock);
                }
                if (mExitRequested) {
                    break;
                }
                // move the callbacks to a temporary vector
                auto callbacks(std::move(serviceThreadCallbackQueue));
                lock.unlock();
                // and make sure to call them without our lock held
                for (auto[handler, callback, user]: callbacks) {
                    handler->post(user, callback);
                }
            } while (true);
        });
    }
}

DriverBase::~DriverBase() noexcept {
    if constexpr (UTILS_HAS_THREADING) {
        // quit our service thread
        std::unique_lock<std::mutex> lock(mServiceThreadLock);
        mExitRequested = true;
        mServiceThreadCondition.notify_one();
        lock.unlock();
        mServiceThread.join();
    }
    delete mDispatcher;
}

class DriverBase::CallbackDataDetails : public DriverBase::CallbackData {
    UTILS_UNUSED DriverBase* mAllocator;
public:
    explicit CallbackDataDetails(DriverBase* allocator) : mAllocator(allocator) {}
};

DriverBase::CallbackData* DriverBase::CallbackData::obtain(DriverBase* allocator) {
    // todo: use a pool
    return new CallbackDataDetails(allocator);
}

void DriverBase::CallbackData::release(CallbackData* data) {
    // todo: use a pool
    delete static_cast<CallbackDataDetails*>(data);
}

void DriverBase::scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) {
    if (handler && UTILS_HAS_THREADING) {
        std::lock_guard<std::mutex> lock(mServiceThreadLock);
        mServiceThreadCallbackQueue.emplace_back(handler, callback, user);
        mServiceThreadCondition.notify_one();
    } else {
        std::lock_guard<std::mutex> lock(mPurgeLock);
        mCallbacks.emplace_back(user, callback);
    }
}

void DriverBase::purge() noexcept {
    decltype(mCallbacks) callbacks;
    std::unique_lock<std::mutex> lock(mPurgeLock);
    std::swap(callbacks, mCallbacks);
    lock.unlock(); // don't remove this, it ensures callbacks are called without lock held
    for (auto& item : callbacks) {
        item.second(item.first);
    }
}

void DriverBase::scheduleDestroySlow(BufferDescriptor&& buffer) noexcept {
    scheduleCallback(buffer.getHandler(), [buffer = std::move(buffer)]() {
        // user callback is called when BufferDescriptor gets destroyed
    });
}

// This is called from an async driver method so it's in the GL thread, but purge is called
// on the user thread. This is typically called 0 or 1 times per frame.

void DriverBase::debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept {
    if constexpr (bool(FILAMENT_DEBUG_COMMANDS > FILAMENT_DEBUG_COMMANDS_NONE)) {
        if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_LOG)) {
            utils::slog.d << methodName << utils::io::endl;
        }
        if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
            SYSTRACE_CONTEXT();
            SYSTRACE_NAME_BEGIN(methodName);

            if (!synchronous) {
                cmds->queueCommand([=]() {
                    SYSTRACE_CONTEXT();
                    SYSTRACE_NAME_BEGIN(methodName);
                });
            }
        }
    }
}

void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept {
    if constexpr (bool(FILAMENT_DEBUG_COMMANDS > FILAMENT_DEBUG_COMMANDS_NONE)) {
        if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
            if (!synchronous) {
                cmds->queueCommand([]() {
                    SYSTRACE_CONTEXT();
                    SYSTRACE_NAME_END();
                });
            }
            SYSTRACE_CONTEXT();
            SYSTRACE_NAME_END();
        }
    }
}

Driver::~Driver() noexcept = default;

void Driver::execute(std::function<void(void)> fn) noexcept {
    fn();
}

size_t Driver::getElementTypeSize(ElementType type) noexcept {
    switch (type) {
        case ElementType::BYTE:     return sizeof(int8_t);
        case ElementType::BYTE2:    return sizeof(byte2);
        case ElementType::BYTE3:    return sizeof(byte3);
        case ElementType::BYTE4:    return sizeof(byte4);
        case ElementType::UBYTE:    return sizeof(uint8_t);
        case ElementType::UBYTE2:   return sizeof(ubyte2);
        case ElementType::UBYTE3:   return sizeof(ubyte3);
        case ElementType::UBYTE4:   return sizeof(ubyte4);
        case ElementType::SHORT:    return sizeof(int16_t);
        case ElementType::SHORT2:   return sizeof(short2);
        case ElementType::SHORT3:   return sizeof(short3);
        case ElementType::SHORT4:   return sizeof(short4);
        case ElementType::USHORT:   return sizeof(uint16_t);
        case ElementType::USHORT2:  return sizeof(ushort2);
        case ElementType::USHORT3:  return sizeof(ushort3);
        case ElementType::USHORT4:  return sizeof(ushort4);
        case ElementType::INT:      return sizeof(int32_t);
        case ElementType::UINT:     return sizeof(uint32_t);
        case ElementType::FLOAT:    return sizeof(float);
        case ElementType::FLOAT2:   return sizeof(float2);
        case ElementType::FLOAT3:   return sizeof(float3);
        case ElementType::FLOAT4:   return sizeof(float4);
        case ElementType::HALF:     return sizeof(half);
        case ElementType::HALF2:    return sizeof(half2);
        case ElementType::HALF3:    return sizeof(half3);
        case ElementType::HALF4:    return sizeof(half4);
    }
}

} // namespace backend
} // namespace filament