예제 #1
0
파일: qcsg.c 프로젝트: 6779660/halflife
/*
===========
CSGBrush
===========
*/
void CSGBrush (int brushnum)
{
	int			hull;
	brush_t		*b1, *b2;
	brushhull_t	*bh1, *bh2;
	int			bn;
	qboolean	overwrite;
	int			i;
	bface_t		*f, *f2, *next, *fcopy;
	bface_t		*outside, *oldoutside;
	entity_t	*e;
	vec_t		area;

	SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL);

	b1 = &mapbrushes[brushnum];

	e = &entities[b1->entitynum];

	for (hull = 0 ; hull<NUM_HULLS ; hull++)
	{
		bh1 = &b1->hulls[hull];

		// set outside to a copy of the brush's faces
		outside = CopyFacesToOutside (bh1);
		overwrite = false;

		for (bn=0 ; bn<e->numbrushes ; bn++)
		{
			// see if b2 needs to clip a chunk out of b1

			if (bn==brushnum)
			{
				overwrite = true;	// later brushes now overwrite
				continue;
			}

			b2 = &mapbrushes[e->firstbrush + bn];
			bh2 = &b2->hulls[hull];

			if (!bh2->faces)
				continue;		// brush isn't in this hull

			// check brush bounding box first
			for (i=0 ; i<3 ; i++)
				if (bh1->mins[i] > bh2->maxs[i] 
				|| bh1->maxs[i] < bh2->mins[i])
					break;
			if (i<3)
				continue;

			// divide faces by the planes of the b2 to find which
			// fragments are inside
		
			f = outside;
			outside = NULL;
			for ( ; f ; f=next)
			{
				next = f->next;

				// check face bounding box first
				for (i=0 ; i<3 ; i++)
					if (bh2->mins[i] > f->maxs[i] 
					|| bh2->maxs[i] < f->mins[i])
						break;
				if (i<3)
				{	// this face doesn't intersect brush2's bbox
					f->next = outside;
					outside = f;
					continue;
				}

				oldoutside = outside;
				fcopy = CopyFace (f);	// save to avoid fake splits

				// throw pieces on the front sides of the planes
				// into the outside list, return the remains on the inside
				for (f2=bh2->faces ; f2 && f ; f2=f2->next)
					f = ClipFace (b1, f, &outside, f2->planenum, overwrite);

				area = f ? WindingArea (f->w) : 0;
				if (f && area < 1.0)
				{
					qprintf ("Entity %i, Brush %i: tiny penetration\n"
						, b1->entitynum, b1->brushnum);
					c_tiny_clip++;
					FreeFace (f);
					f = NULL;
				}
				if (f)
				{
					// there is one convex fragment of the original
					// face left inside brush2
					FreeFace (fcopy);

					if (b1->contents > b2->contents)
					{	// inside a water brush
						f->contents = b2->contents;
						f->next = outside;
						outside = f;
					}
					else	// inside a solid brush
						FreeFace (f);	// throw it away
				}
				else
				{	// the entire thing was on the outside, even
					// though the bounding boxes intersected,
					// which will never happen with axial planes

					// free the fragments chopped to the outside
					while (outside != oldoutside)
					{
						f2 = outside->next;
						FreeFace (outside);
						outside = f2;
					}

					// revert to the original face to avoid
					// unneeded false cuts
					fcopy->next = outside;
					outside = fcopy;
				}
			}

		}

		// all of the faces left in outside are real surface faces
		SaveOutside (b1, hull, outside, b1->contents);
	}
}
예제 #2
0
int Hull::AddContactsHullHull(Separation& sep, const Point3* pVertsA, const Point3* pVertsB,
                              const Transform& trA, const Transform& trB,const Hull& hullA,const Hull& hullB,
                              HullContactCollector* hullContactCollector)
{
    const int maxContacts = hullContactCollector->GetMaxNumContacts();

    Vector3 normalWorld = sep.m_axis;

    // edge->edge contact is always a single point
    if (sep.m_separator == Separation::kFeatureBoth)
    {
        const Hull::Edge& edgeA = hullA.GetEdge(sep.m_featureA);
        const Hull::Edge& edgeB = hullB.GetEdge(sep.m_featureB);

        float ta, tb;
        Line la(pVertsA[edgeA.m_verts[0]], pVertsA[edgeA.m_verts[1]]);
        Line lb(pVertsB[edgeB.m_verts[0]], pVertsB[edgeB.m_verts[1]]);

        Intersect(la, lb, ta, tb);

#ifdef VALIDATE_CONTACT_POINTS
        AssertPointInsideHull(contact.m_points[0].m_pos, trA, hullA);
        AssertPointInsideHull(contact.m_points[0].m_pos, trB, hullB);
#endif


        Point3 posWorld = Lerp(la.m_start, la.m_end, ta);
        float depth = -sep.m_dist;
        Vector3 tangent = Normalize(pVertsA[edgeA.m_verts[1]] - pVertsA[edgeA.m_verts[0]]);

        sep.m_contact = hullContactCollector->BatchAddContactGroup(sep,1,normalWorld,tangent,&posWorld,&depth);

    }
    // face->face contact is polygon
    else
    {
        short faceA = sep.m_featureA;
        short faceB = sep.m_featureB;

        Vector3 tangent;

        // find face of hull A that is most opposite contact axis
        // TODO: avoid having to transform planes here
        if (sep.m_separator == Separation::kFeatureB)
        {
            const Hull::Edge& edgeB = hullB.GetEdge(hullB.GetFaceFirstEdge(faceB));
            tangent = Normalize(pVertsB[edgeB.m_verts[1]] - pVertsB[edgeB.m_verts[0]]);

            Scalar dmin = Scalar::Consts::MaxValue;
            for (short face = 0; face < hullA.m_numFaces; face++)
            {
                Vector3 normal = hullA.GetPlane(face).GetNormal() * trA;
                Scalar d = Dot(normal, sep.m_axis);
                if (d < dmin)
                {
                    dmin = d;
                    faceA = face;
                }
            }
        }
        else
        {
            const Hull::Edge& edgeA = hullA.GetEdge(hullA.GetFaceFirstEdge(faceA));
            tangent = Normalize(pVertsA[edgeA.m_verts[1]] - pVertsA[edgeA.m_verts[0]]);

            Scalar dmin = Scalar::Consts::MaxValue;
            for (short face = 0; face < hullB.m_numFaces; face++)
            {
                Vector3 normal = hullB.GetPlane(face).GetNormal() * trB;
                Scalar d = Dot(normal, -sep.m_axis);
                if (d < dmin)
                {
                    dmin = d;
                    faceB = face;
                }
            }
        }

        Point3 workspace[2][Hull::kMaxVerts];

        // setup initial clip face (minimizing face from hull B)
        int numContacts = 0;
        for (short edge = hullB.GetFaceFirstEdge(faceB); edge != -1; edge = hullB.GetFaceNextEdge(faceB, edge))
            workspace[0][numContacts++] = pVertsB[ hullB.GetEdgeVertex0(faceB, edge) ];

        // clip polygon to back of planes of all faces of hull A that are adjacent to witness face
        Point3* pVtxIn = workspace[0];
        Point3* pVtxOut = workspace[1];

#if 0
        for (short edge = hullA.GetFaceFirstEdge(faceA); edge != -1; edge = hullA.GetFaceNextEdge(faceA, edge))
        {
            Plane planeA = hullA.GetPlane( hullA.GetEdgeOtherFace(edge, faceA) ) * trA;
            numContacts = ClipFace(numContacts, &pVtxIn, &pVtxOut, planeA);
        }
#else
        for (short f = 0; f < hullA.GetNumFaces(); f++)
        {
            Plane planeA = hullA.GetPlane(f) * trA;
            numContacts = ClipFace(numContacts, &pVtxIn, &pVtxOut, planeA);
        }
#endif

        // only keep points that are behind the witness face
        Plane planeA = hullA.GetPlane(faceA) * trA;

        float depths[Hull::kMaxVerts];
        int numPoints = 0;
        for (int i = 0; i < numContacts; i++)
        {
            Scalar d = Dot(planeA, pVtxIn[i]);
            if (IsNegative(d))
            {
                depths[numPoints] = (float)-d;
                pVtxIn[numPoints] = pVtxIn[i];

#ifdef VALIDATE_CONTACT_POINTS
                AssertPointInsideHull(pVtxIn[numPoints], trA, hullA);
                AssertPointInsideHull(pVtxIn[numPoints], trB, hullB);
#endif
                numPoints++;
            }
        }

        //we can also use a persistentManifold/reducer class
        // keep maxContacts points at most
        if (numPoints > 0)
        {
            if (numPoints > maxContacts)
            {
                int step = (numPoints << 8) / maxContacts;

                numPoints = maxContacts;
                for (int i = 0; i < numPoints; i++)
                {
                    int nth = (step * i) >> 8;

                    depths[i] = depths[nth];
                    pVtxIn[i] = pVtxIn[nth];


#ifdef VALIDATE_CONTACT_POINTS
                    AssertPointInsideHull(contact.m_points[i].m_pos, trA, hullA);
                    AssertPointInsideHull(contact.m_points[i].m_pos, trB, hullB);
#endif
                }
            }

            sep.m_contact = hullContactCollector->BatchAddContactGroup(sep,numPoints,normalWorld,tangent,pVtxIn,depths);

        }
        return numPoints;
    }
bool VertexCoordRemapper::GetNextFaceCoordinates(Coords *result)
{
//    DEBUG_DEBUG("mesh update get face coords");
    result->tex_c = tex_coords;
    result->vertex_c = s_vertex_coords;
    // if we have some faces left over from a previous clipping operation, give
    // one of those first:
    if (GiveClipFaceResult(result)) return true;
    // when 180 degree bounds correction is working, we'll have two nodes.
    if (done_node)
    {
        do
        {
            // this will search the tree for the next leaf node.
            tree_node_id = tree.GetNext();
            if (!tree_node_id)
            {
                // we've reached last one
                return false;
            }
        }
        // some of the verticies may have arrived from undefined transformations
        // if this is one, skip it and try to find another.
        while ((tree.nodes[tree_node_id].flags & (transform_fail_flag * 15)));
            
        // find the coordinates from the tree node
        result->vertex_c = tree.nodes[tree_node_id].verts;
        // check that the transformation is properly defined.

        tree.GetInputCoordinates(tree_node_id, tex_coords);
        // if the node has a discontinuity, we want to split it into two
        // faces and return each one on consecutive calls.
        discontinuity_flags =
                 (tree.nodes[tree_node_id].flags / vertex_side_flag_start) % 16;
        if (discontinuity_flags)
        {
            done_node = false;
            // flip the marked nodes to the other side. copy the coordinates 1st
            result->vertex_c = s_vertex_coords;            
            for (short unsigned int x = 0; x < 2; x++)
            {
                for (short unsigned int y = 0; y < 2; y++)
                {
                      s_vertex_coords[x][y][0] =
                                        tree.nodes[tree_node_id].verts[x][y][0];
                      s_vertex_coords[x][y][1] =
                                        tree.nodes[tree_node_id].verts[x][y][1];
                      if (discontinuity_flags & (1 << (x*2 + y)))
                      {
                          DiscontinuityFlip(s_vertex_coords[x][y]);
                      }
                }
            }
        }
    } else {
        // we flip the other vertices to the ones we did last time.
        done_node = true;
        for (short unsigned int x = 0; x < 2; x++)
        {
            for (short unsigned int y = 0; y < 2; y++)
            {
                  s_vertex_coords[x][y][0] =
                                        tree.nodes[tree_node_id].verts[x][y][0];
                  s_vertex_coords[x][y][1] =
                                        tree.nodes[tree_node_id].verts[x][y][1];
                  if (!(discontinuity_flags & (1 << (x*2 + y))))
                  {
                      DiscontinuityFlip(s_vertex_coords[x][y]);
                  }
            }
        }
    }
    // if we are doing circular cropping, clip the face so it makes the shape
    if (circle_crop)
    {
        // If all points are within the radius, then don't clip
//        HuginBase::SrcPanoImage *src_img = visualization_state->GetSrcImage(image_number);
        if (   image->isInside(vigra::Point2D(int(result->tex_c[0][0][0] * width),
                                                int(result->tex_c[0][0][1] * height)))
            && image->isInside(vigra::Point2D(int(result->tex_c[0][1][0] * width),
                                                int(result->tex_c[0][1][1] * height)))
            && image->isInside(vigra::Point2D(int(result->tex_c[1][0][0] * width),
                                                int(result->tex_c[1][0][1] * height)))
            && image->isInside(vigra::Point2D(int(result->tex_c[1][1][0] * width),
                                                int(result->tex_c[1][1][1] * height))))
        {
            // all inside, doesn't need clipping.
            return true;
        }
        // we do need to clip:     
        ClipFace(result);
        // if there was anything left, return the first face and leave the rest
        // for later.
        if (GiveClipFaceResult(result)) return true;
        // we clipped to nothing... try and get another face: from the top...
        return (GetNextFaceCoordinates(result));
    }
    return true;
}