Ejemplo n.º 1
0
	// Constructor. Copy the provided picoSurface_t structure into this object
	RenderablePicoSurface::RenderablePicoSurface (picoSurface_t* surf) :
		_originalShaderName(""), _mappedShaderName("")
	{
		// Get the shader from the picomodel struct.
		picoShader_t* shader = PicoGetSurfaceShader(surf);
		if (shader != 0) {
			_originalShaderName = PicoGetShaderName(shader);
		}

		// Capture the shader
		_shader = GlobalShaderCache().capture(_originalShaderName);
		if (_shader)
			_mappedShaderName = _originalShaderName; // no skin at this time

		// Get the number of vertices and indices, and reserve capacity in our vectors in advance
		// by populating them with empty structs.
		const int nVerts = PicoGetSurfaceNumVertexes(surf);
		_nIndices = PicoGetSurfaceNumIndexes(surf);
		_vertices.resize(nVerts);
		_indices.resize(_nIndices);

		// Stream in the vertex data from the raw struct, expanding the local AABB to include
		// each vertex.
		for (int vNum = 0; vNum < nVerts; ++vNum) {
			Vertex3f vertex(PicoGetSurfaceXYZ(surf, vNum));
			_localAABB.includePoint(vertex);
			_vertices[vNum].vertex = vertex;
			_vertices[vNum].normal = Normal3f(PicoGetSurfaceNormal(surf, vNum));
			_vertices[vNum].texcoord = TexCoord2f(PicoGetSurfaceST(surf, 0, vNum));
		}

		// Stream in the index data
		picoIndex_t* ind = PicoGetSurfaceIndexes(surf, 0);
		for (unsigned int i = 0; i < _nIndices; i++)
			_indices[i] = ind[i];
	}
// Constructor. Copy the provided picoSurface_t structure into this object
RenderablePicoSurface::RenderablePicoSurface(picoSurface_t* surf,
											 const std::string& fExt)
: _shaderName(""),
  _dlRegular(0),
  _dlProgramVcol(0),
  _dlProgramNoVCol(0)
{
	// Get the shader from the picomodel struct. If this is a LWO model, use
	// the material name to select the shader, while for an ASE model the
	// bitmap path should be used.
	picoShader_t* shader = PicoGetSurfaceShader(surf);
	std::string rawName = "";

	if (shader != 0)
	{
		if (fExt == "lwo")
		{
			_shaderName = PicoGetShaderName(shader);
		}
		else if (fExt == "ase")
		{
			rawName = PicoGetShaderName(shader);
			std::string rawMapName = PicoGetShaderMapName(shader);
			_shaderName = cleanupShaderName(rawMapName);
		}
	}

	// If shader not found, fallback to alternative if available
	// _shaderName is empty if the ase material has no BITMAP
	// materialIsValid is false if _shaderName is not an existing shader
	if ((_shaderName.empty() || !GlobalMaterialManager().materialExists(_shaderName)) &&
		!rawName.empty())
	{
		_shaderName = cleanupShaderName(rawName);
	}

	// Capturing the shader happens later on when we have a RenderSystem reference

    // Get the number of vertices and indices, and reserve capacity in our
    // vectors in advance by populating them with empty structs.
    int nVerts = PicoGetSurfaceNumVertexes(surf);
    _nIndices = PicoGetSurfaceNumIndexes(surf);
    _vertices.resize(nVerts);
    _indices.resize(_nIndices);

    // Stream in the vertex data from the raw struct, expanding the local AABB
    // to include each vertex.
    for (int vNum = 0; vNum < nVerts; ++vNum) {

    	// Get the vertex position and colour
		Vertex3f vertex(PicoGetSurfaceXYZ(surf, vNum));

		// Expand the AABB to include this new vertex
    	_localAABB.includePoint(vertex);

    	_vertices[vNum].vertex = vertex;
    	_vertices[vNum].normal = Normal3f(PicoGetSurfaceNormal(surf, vNum));
    	_vertices[vNum].texcoord = TexCoord2f(PicoGetSurfaceST(surf, 0, vNum));
    	_vertices[vNum].colour =
    		getColourVector(PicoGetSurfaceColor(surf, 0, vNum));
    }

    // Stream in the index data
    picoIndex_t* ind = PicoGetSurfaceIndexes(surf, 0);
    for (unsigned int i = 0; i < _nIndices; i++)
    	_indices[i] = ind[i];

	// Calculate the tangent and bitangent vectors
	calculateTangents();

	// Construct the DLs
	createDisplayLists();
}
Ejemplo n.º 3
0
void CPicoSurface::Draw(int state, IShader *pShader, int rflags)
{
  int j;

  if( !(rflags & (DRAW_RF_SEL_OUTLINE|DRAW_RF_SEL_FILL|DRAW_RF_XY)) )
  {
    if(state & DRAW_GL_TEXTURE_2D)
    {
      g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number);
      if( (rflags & DRAW_RF_CAM) && (pShader->getFlags() & QER_ALPHAFUNC) ) {
        int nFunc = 0;
        float fRef = 0.f;

        g_QglTable.m_pfn_qglColor4f( 1.f, 1.f, 1.f, 1.f ); // identity

        g_QglTable.m_pfn_qglEnable( GL_ALPHA_TEST );

        pShader->getAlphaFunc( &nFunc, &fRef );
	      g_QglTable.m_pfn_qglAlphaFunc( nFunc, fRef );
      }
    }
    else
    {
      //g_QglTable.m_pfn_qglColor3fv( pShader->getTexture()->color );
/*      g_QglTable.m_pfn_qglEnableClientState(GL_COLOR_ARRAY);*/
    }

    if( !(state & DRAW_GL_WIRE) && (pShader->getFlags() & QER_CULL) )
    {
      if( pShader->getCull() == 2 )
      {
        g_QglTable.m_pfn_qglDisable( GL_CULL_FACE );
        g_QglTable.m_pfn_qglPolygonMode (GL_FRONT, GL_FILL);
      }
      else // is 1
      {
        g_QglTable.m_pfn_qglCullFace( GL_BACK );
      }
    }
  }

  switch( PicoGetSurfaceType(m_pSurface) )
  {
  case PICO_TRIANGLES:  g_QglTable.m_pfn_qglBegin(GL_TRIANGLES);
                        for (j=0; j<PicoGetSurfaceNumIndexes(m_pSurface); j++)
                        {
	                      g_QglTable.m_pfn_qglNormal3fv(PicoGetSurfaceNormal(m_pSurface,PicoGetSurfaceIndex(m_pSurface,j)));
							
						  if( !(rflags & (DRAW_RF_SEL_OUTLINE|DRAW_RF_SEL_FILL|DRAW_RF_XY)) ) {
                            if(state & DRAW_GL_TEXTURE_2D) {
                              g_QglTable.m_pfn_qglTexCoord2fv(PicoGetSurfaceST(m_pSurface,0,PicoGetSurfaceIndex(m_pSurface,j)));
							} else {
                              picoByte_t *vertexColor = PicoGetSurfaceColor(m_pSurface,0,PicoGetSurfaceIndex(m_pSurface,j));
                              //% g_QglTable.m_pfn_qglColor4f( vertexColor[ 0 ] / 255.f,
                              //%                              vertexColor[ 1 ] / 255.f,
                              //%                              vertexColor[ 2 ] / 255.f,
                              //%                              vertexColor[ 3 ] / 255.f );
                              g_QglTable.m_pfn_qglColor4ubv( vertexColor );
                            }
						  }
                          g_QglTable.m_pfn_qglVertex3fv( PicoGetSurfaceXYZ( m_pSurface, PicoGetSurfaceIndex( m_pSurface, j ) ) );
                        }
                        g_QglTable.m_pfn_qglEnd();
                        /*g_QglTable.m_pfn_qglVertexPointer( 3, GL_FLOAT, 0, PicoGetSurfaceXYZ( m_pSurface, 0 ) );
						g_QglTable.m_pfn_qglNormalPointer( GL_FLOAT, 0, PicoGetSurfaceNormal( m_pSurface, 0 ) );
						if( !(rflags & (DRAW_RF_SEL_OUTLINE|DRAW_RF_SEL_FILL|DRAW_RF_XY)) ) {
                          if( state & DRAW_GL_TEXTURE_2D ) {
						    g_QglTable.m_pfn_qglTexCoordPointer( 2, GL_FLOAT, 0, PicoGetSurfaceST( m_pSurface, 0, 0 ) );                            
						  } else {
                            g_QglTable.m_pfn_qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, PicoGetSurfaceColor( m_pSurface, 0, 0 ) );
						  }
						}
						g_QglTable.m_pfn_qglDrawElements( GL_TRIANGLES, PicoGetSurfaceNumIndexes( m_pSurface ), GL_UNSIGNED_INT, PicoGetSurfaceIndexes( m_pSurface, 0 ) );*/

                        /*g_QglTable.m_pfn_qglColor3f( 0.f, .5f, 1.f );
						g_QglTable.m_pfn_qglBegin( GL_LINES );
						for( int i = 0; i < PicoGetSurfaceNumIndexes( m_pSurface ); i++ ) {
						  vec3_t outerpoint;
						  VectorMA( PicoGetSurfaceXYZ( m_pSurface, PicoGetSurfaceIndex( m_pSurface, i ) ), .3f, PicoGetSurfaceNormal( m_pSurface, PicoGetSurfaceIndex( m_pSurface, i ) ), outerpoint );
						  g_QglTable.m_pfn_qglVertex3fv( PicoGetSurfaceXYZ( m_pSurface, PicoGetSurfaceIndex( m_pSurface, i ) ) );
						  g_QglTable.m_pfn_qglVertex3fv( outerpoint );
						}
						g_QglTable.m_pfn_qglEnd();*/

                        break;
  default:              Sys_Printf( "ERROR: Unsupported Pico Surface Type: %i", PicoGetSurfaceType(m_pSurface) );
                        break;
  }

  if( !(rflags & (DRAW_RF_SEL_OUTLINE|DRAW_RF_SEL_FILL|DRAW_RF_XY)) )
  {
    if( (state & DRAW_GL_TEXTURE_2D) && (rflags & DRAW_RF_CAM) && (pShader->getFlags() & QER_ALPHAFUNC) ) {
      g_QglTable.m_pfn_qglDisable( GL_ALPHA_TEST );
    }

/*	if(!(state & DRAW_GL_TEXTURE_2D)) {
      g_QglTable.m_pfn_qglDisableClientState(GL_COLOR_ARRAY);
	}*/

    if( !(state & DRAW_GL_WIRE) && (pShader->getFlags() & QER_CULL) )
    {
      if( pShader->getCull() == 2 )
      {
        g_QglTable.m_pfn_qglPolygonMode (GL_FRONT, GL_LINE);
        g_QglTable.m_pfn_qglEnable( GL_CULL_FACE );
      }
      else // is 1
      {
        g_QglTable.m_pfn_qglCullFace( GL_FRONT );
      }
    }
  }
}
Ejemplo n.º 4
0
void InsertModel(char *name, int frame, matrix_t transform, matrix_t nTransform, remap_t * remap, shaderInfo_t * celShader, int eNum, int castShadows,
				 int recvShadows, int spawnFlags, float lightmapScale, int lightmapSampleSize, float shadeAngle)
{
	int             i, j, k, s, numSurfaces;
	matrix_t        identity;
	picoModel_t    *model;
	picoShader_t   *shader;
	picoSurface_t  *surface;
	shaderInfo_t   *si;
	mapDrawSurface_t *ds;
	bspDrawVert_t  *dv;
	char           *picoShaderName;
	char            shaderName[MAX_QPATH];
	picoVec_t      *xyz, *normal, *st;
	byte           *color;
	picoIndex_t    *indexes;
	remap_t        *rm, *glob;
	double          normalEpsilon_save;
	double          distanceEpsilon_save;


	/* get model */
	model = LoadModel(name, frame);
	if(model == NULL)
		return;

	/* handle null matrix */
	if(transform == NULL)
	{
		MatrixIdentity(identity);
		transform = identity;
	}

	/* create transform matrix for normals */
#if 0
	MatrixCopy(transform, nTransform);
	if(MatrixInverse(nTransform))
	{
		Sys_FPrintf(SYS_VRB, "WARNING: Can't invert model transform matrix, using transpose instead\n");
		MatrixTranspose(transform, nTransform);
	}
#endif

	/* fix bogus lightmap scale */
	if(lightmapScale <= 0.0f)
		lightmapScale = 1.0f;

	/* fix bogus shade angle */
	if(shadeAngle <= 0.0f)
		shadeAngle = 0.0f;

	/* each surface on the model will become a new map drawsurface */
	numSurfaces = PicoGetModelNumSurfaces(model);
	//% Sys_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces );
	for(s = 0; s < numSurfaces; s++)
	{
		/* get surface */
		surface = PicoGetModelSurface(model, s);
		if(surface == NULL)
			continue;

		/* only handle triangle surfaces initially (fixme: support patches) */
		if(PicoGetSurfaceType(surface) != PICO_TRIANGLES)
			continue;

		/* fix the surface's normals */
		PicoFixSurfaceNormals(surface);

		/* allocate a surface (ydnar: gs mods) */
		ds = AllocDrawSurface(SURFACE_TRIANGLES);
		ds->entityNum = eNum;
		ds->castShadows = castShadows;
		ds->recvShadows = recvShadows;

		/* get shader name */
		shader = PicoGetSurfaceShader(surface);
		if(shader == NULL)
			picoShaderName = "";
		else
			picoShaderName = PicoGetShaderName(shader);

		/* handle shader remapping */
		glob = NULL;
		for(rm = remap; rm != NULL; rm = rm->next)
		{
			if(rm->from[0] == '*' && rm->from[1] == '\0')
				glob = rm;
			else if(!Q_stricmp(picoShaderName, rm->from))
			{
				Sys_FPrintf(SYS_VRB, "Remapping %s to %s\n", picoShaderName, rm->to);
				picoShaderName = rm->to;
				glob = NULL;
				break;
			}
		}

		if(glob != NULL)
		{
			Sys_FPrintf(SYS_VRB, "Globbing %s to %s\n", picoShaderName, glob->to);
			picoShaderName = glob->to;
		}

		/* shader renaming for sof2 */
		if(renameModelShaders)
		{
			strcpy(shaderName, picoShaderName);
			StripExtension(shaderName);
			if(spawnFlags & 1)
				strcat(shaderName, "_RMG_BSP");
			else
				strcat(shaderName, "_BSP");
			si = ShaderInfoForShader(shaderName);
		}
		else
		{
			si = ShaderInfoForShader(picoShaderName);

			// Tr3B: HACK to support the messy Doom 3 materials provided by .ASE files
			if(!si->explicitDef)
			{
				picoShaderName = PicoGetShaderMapName(shader);

				Q_strncpyz(shaderName, picoShaderName, sizeof(shaderName));
				StripExtension(shaderName);

				i = 0;
				while(shaderName[i])
				{
					if(shaderName[i] == '\\')
						shaderName[i] = '/';
					i++;
				}

				if(strstr(shaderName, "base/"))
				{
					si = ShaderInfoForShader(strstr(shaderName, "base/") + strlen("base/"));
					Sys_FPrintf(SYS_WRN, "WARNING: Applied .ASE material loader HACK to '%s' -> '%s'\n", picoShaderName, si->shader);
				}

			}
		}

		/* set shader */
		ds->shaderInfo = si;

		/* force to meta? */
		if((si != NULL && si->forceMeta) || (spawnFlags & 4))	/* 3rd bit */
			ds->type = SURFACE_FORCED_META;

		/* fix the surface's normals (jal: conditioned by shader info) */
		//if(!(spawnFlags & 64) && (shadeAngle == 0.0f || ds->type != SURFACE_FORCED_META))
		//	PicoFixSurfaceNormals(surface);

		/* set sample size */
		if(lightmapSampleSize > 0.0f)
			ds->sampleSize = lightmapSampleSize;

		/* set lightmap scale */
		if(lightmapScale > 0.0f)
			ds->lightmapScale = lightmapScale;

		/* set shading angle */
		if(shadeAngle > 0.0f)
			ds->shadeAngleDegrees = shadeAngle;

		/* set particulars */
		ds->numVerts = PicoGetSurfaceNumVertexes(surface);
		ds->verts = safe_malloc(ds->numVerts * sizeof(ds->verts[0]));
		memset(ds->verts, 0, ds->numVerts * sizeof(ds->verts[0]));

		ds->numIndexes = PicoGetSurfaceNumIndexes(surface);
		ds->indexes = safe_malloc(ds->numIndexes * sizeof(ds->indexes[0]));
		memset(ds->indexes, 0, ds->numIndexes * sizeof(ds->indexes[0]));

		/* copy vertexes */
		for(i = 0; i < ds->numVerts; i++)
		{
			/* get vertex */
			dv = &ds->verts[i];

			/* xyz and normal */
			xyz = PicoGetSurfaceXYZ(surface, i);
			VectorCopy(xyz, dv->xyz);
			MatrixTransformPoint2(transform, dv->xyz);

			normal = PicoGetSurfaceNormal(surface, i);
			VectorCopy(normal, dv->normal);
			MatrixTransformNormal2(nTransform, dv->normal);
			VectorNormalize2(dv->normal, dv->normal);

			/* ydnar: tek-fu celshading support for flat shaded shit */
			if(flat)
			{
				dv->st[0] = si->stFlat[0];
				dv->st[1] = si->stFlat[1];
			}

			/* ydnar: gs mods: added support for explicit shader texcoord generation */
			else if(si->tcGen)
			{
				/* project the texture */
				dv->st[0] = DotProduct(si->vecs[0], dv->xyz);
				dv->st[1] = DotProduct(si->vecs[1], dv->xyz);
			}

			/* normal texture coordinates */
			else
			{
				st = PicoGetSurfaceST(surface, 0, i);
				dv->st[0] = st[0];
				dv->st[1] = st[1];
			}

			/* set lightmap/color bits */
			color = PicoGetSurfaceColor(surface, 0, i);

			dv->paintColor[0] = color[0] / 255.0f;
			dv->paintColor[1] = color[1] / 255.0f;
			dv->paintColor[2] = color[2] / 255.0f;
			dv->paintColor[3] = color[3] / 255.0f;

			for(j = 0; j < MAX_LIGHTMAPS; j++)
			{
				dv->lightmap[j][0] = 0.0f;
				dv->lightmap[j][1] = 0.0f;

				dv->lightColor[j][0] = 255;
				dv->lightColor[j][1] = 255;
				dv->lightColor[j][2] = 255;
				dv->lightColor[j][3] = 255;
			}
		}

		/* copy indexes */
		indexes = PicoGetSurfaceIndexes(surface, 0);
		for(i = 0; i < ds->numIndexes; i++)
			ds->indexes[i] = indexes[i];

		/* set cel shader */
		ds->celShader = celShader;

		/* ydnar: giant hack land: generate clipping brushes for model triangles */
		if(si->clipModel || (spawnFlags & 2))	/* 2nd bit */
		{
			vec3_t          points[4], backs[3];
			vec4_t          plane, reverse, pa, pb, pc;


			/* temp hack */
			if(!si->clipModel &&
			   (((si->compileFlags & C_TRANSLUCENT) && !(si->compileFlags & C_COLLISION)) || !(si->compileFlags & C_SOLID)))
				continue;

			/* walk triangle list */
			for(i = 0; i < ds->numIndexes; i += 3)
			{
				/* overflow hack */
				AUTOEXPAND_BY_REALLOC(mapplanes, (nummapplanes + 64) << 1, allocatedmapplanes, 1024);

				/* make points and back points */
				for(j = 0; j < 3; j++)
				{
					/* get vertex */
					dv = &ds->verts[ds->indexes[i + j]];

					/* copy xyz */
					VectorCopy(dv->xyz, points[j]);
					VectorCopy(dv->xyz, backs[j]);

					/* find nearest axial to normal and push back points opposite */
					/* note: this doesn't work as well as simply using the plane of the triangle, below */
					for(k = 0; k < 3; k++)
					{
						if(fabs(dv->normal[k]) >= fabs(dv->normal[(k + 1) % 3]) &&
						   fabs(dv->normal[k]) >= fabs(dv->normal[(k + 2) % 3]))
						{
							backs[j][k] += dv->normal[k] < 0.0f ? 64.0f : -64.0f;
							break;
						}
					}
				}

				VectorCopy(points[0], points[3]);	// for cyclic usage

				/* make plane for triangle */
				// div0: add some extra spawnflags:
				//   0: snap normals to axial planes for extrusion
				//   8: extrude with the original normals
				//  16: extrude only with up/down normals (ideal for terrain)
				//  24: extrude by distance zero (may need engine changes)
				if(PlaneFromPoints(plane, points[0], points[1], points[2], qtrue))
				{
					vec3_t          bestNormal;
					float           backPlaneDistance = 2;

					if(spawnFlags & 8)	// use a DOWN normal
					{
						if(spawnFlags & 16)
						{
							// 24: normal as is, and zero width (broken)
							VectorCopy(plane, bestNormal);
						}
						else
						{
							// 8: normal as is
							VectorCopy(plane, bestNormal);
						}
					}
					else
					{
						if(spawnFlags & 16)
						{
							// 16: UP/DOWN normal
							VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
						}
						else
						{
							// 0: axial normal
							if(fabs(plane[0]) > fabs(plane[1]))	// x>y
								if(fabs(plane[1]) > fabs(plane[2]))	// x>y, y>z
									VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
								else	// x>y, z>=y
								if(fabs(plane[0]) > fabs(plane[2]))	// x>z, z>=y
									VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
								else	// z>=x, x>y
									VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
							else	// y>=x
							if(fabs(plane[1]) > fabs(plane[2]))	// y>z, y>=x
								VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
							else	// z>=y, y>=x
								VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
						}
					}

					/* build a brush */
					buildBrush = AllocBrush(48);
					buildBrush->entityNum = mapEntityNum;
					buildBrush->original = buildBrush;
					buildBrush->contentShader = si;
					buildBrush->compileFlags = si->compileFlags;
					buildBrush->contentFlags = si->contentFlags;

					buildBrush->generatedClipBrush = qtrue;

					normalEpsilon_save = normalEpsilon;
					distanceEpsilon_save = distanceEpsilon;

					if(si->compileFlags & C_STRUCTURAL)	// allow forced structural brushes here
					{
						buildBrush->detail = qfalse;

						// only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
						if(normalEpsilon > 0)
							normalEpsilon = 0;
						if(distanceEpsilon > 0)
							distanceEpsilon = 0;
					}
					else
						buildBrush->detail = qtrue;

					/* regenerate back points */
					for(j = 0; j < 3; j++)
					{
						/* get vertex */
						dv = &ds->verts[ds->indexes[i + j]];

						// shift by some units
						VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]);	// 64 prevents roundoff errors a bit
					}

					/* make back plane */
					VectorScale(plane, -1.0f, reverse);
					reverse[3] = -plane[3];
					if((spawnFlags & 24) != 24)
						reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
					// that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)

					if(PlaneFromPoints(pa, points[2], points[1], backs[1], qtrue) &&
					   PlaneFromPoints(pb, points[1], points[0], backs[0], qtrue) && PlaneFromPoints(pc, points[0], points[2], backs[2], qtrue))
					{
						/* set up brush sides */
						buildBrush->numsides = 5;
						buildBrush->sides[0].shaderInfo = si;
						for(j = 1; j < buildBrush->numsides; j++)
							buildBrush->sides[j].shaderInfo = NULL;	// don't emit these faces as draw surfaces, should make smaller BSPs; hope this works

						buildBrush->sides[0].planenum = FindFloatPlane(plane, plane[3], 3, points);
						buildBrush->sides[1].planenum = FindFloatPlane(pa, pa[3], 2, &points[1]);	// pa contains points[1] and points[2]
						buildBrush->sides[2].planenum = FindFloatPlane(pb, pb[3], 2, &points[0]);	// pb contains points[0] and points[1]
						buildBrush->sides[3].planenum = FindFloatPlane(pc, pc[3], 2, &points[2]);	// pc contains points[2] and points[0] (copied to points[3]
						buildBrush->sides[4].planenum = FindFloatPlane(reverse, reverse[3], 3, backs);
					}
					else
					{
						free(buildBrush);
						continue;
					}

					normalEpsilon = normalEpsilon_save;
					distanceEpsilon = distanceEpsilon_save;

					/* add to entity */
					if(CreateBrushWindings(buildBrush))
					{
						AddBrushBevels();
						//% EmitBrushes( buildBrush, NULL, NULL );
						buildBrush->next = entities[mapEntityNum].brushes;
						entities[mapEntityNum].brushes = buildBrush;
						entities[mapEntityNum].numBrushes++;
					}
					else
						free(buildBrush);
				}
			}
		}
	}
}