Ejemplo n.º 1
0
/*
=============
R_PlaneForSurface
=============
*/
void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {
	srfTriangles_t  *tri;
	srfPoly_t		*poly;
	drawVert_t    *v1, *v2, *v3;
	vec4_t			plane4;

	if (!surfType) {
		Com_Memset (plane, 0, sizeof(*plane));
		plane->normal[0] = 1;
		return;
	}
	switch (*surfType) {
	case SF_TRIANGLES:
		tri = (srfTriangles_t *)surfType;
		v1 = tri->verts + tri->indexes[0];
		v2 = tri->verts + tri->indexes[1];
		v3 = tri->verts + tri->indexes[2];
		PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
		VectorCopy( plane4, plane->normal );
		plane->dist = plane4[3];
		return;
	case SF_POLY:
		poly = (srfPoly_t *)surfType;
		PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
		VectorCopy( plane4, plane->normal ); 
		plane->dist = plane4[3];
		return;
	default:
		Com_Memset (plane, 0, sizeof(*plane));
		plane->normal[0] = 1;		
		return;
	}
}
Ejemplo n.º 2
0
qboolean CM_GenerateFacetFor4Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
	float	dist;
	int		i;
	vec4_t	plane;

	// if we can't generate a valid plane for the points, ignore the facet
	if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
		f->numBoundaries = 0;
		return qfalse;
	}

	// if the fourth point is also on the plane, we can make a quad facet
	dist = DotProduct( d->xyz, f->surface ) - f->surface[3];
	if ( fabs( dist ) > PLANAR_EPSILON ) {
		f->numBoundaries = 0;
		return qfalse;
	}

	// make boundaries
	f->numBoundaries = 4;

	CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
	CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
	CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, d->xyz );
	CM_GenerateBoundaryForPoints( f->boundaries[3], f->surface, d->xyz, a->xyz );

	VectorCopy( a->xyz, f->points[0] );
	VectorCopy( b->xyz, f->points[1] );
	VectorCopy( c->xyz, f->points[2] );
	VectorCopy( d->xyz, f->points[3] );

	for (i = 1; i < 4; i++)
	{
		if ( !PlaneFromPoints( plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
			f->numBoundaries = 0;
			return qfalse;
		}

		if (DotProduct(f->surface, plane) < 0.9) {
			f->numBoundaries = 0;
			return qfalse;
		}
	}

	TextureMatrixFromPoints( f, a, b, c );

	return qtrue;
}
Ejemplo n.º 3
0
void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {
	srfTriangles_t	*tri;
	srfPoly_t		*poly;
	drawVert_t		*v1, *v2, *v3;
	vector4			plane4;

	if (!surfType) {
		memset (plane, 0, sizeof(*plane));
		plane->normal.x = 1;
		return;
	}
	switch (*surfType) {
	case SF_FACE:
		*plane = ((srfSurfaceFace_t *)surfType)->plane;
		return;
	case SF_TRIANGLES:
		tri = (srfTriangles_t *)surfType;
		v1 = tri->verts + tri->indexes[0];
		v2 = tri->verts + tri->indexes[1];
		v3 = tri->verts + tri->indexes[2];
		PlaneFromPoints( &plane4, &v1->xyz, &v2->xyz, &v3->xyz );
		VectorCopy( (vector3 *)&plane4, &plane->normal ); 
		plane->dist = plane4.w;
		return;
	case SF_POLY:
		poly = (srfPoly_t *)surfType;
		PlaneFromPoints( &plane4, &poly->verts[0].xyz, &poly->verts[1].xyz, &poly->verts[2].xyz );
		VectorCopy( (vector3 *)&plane4, &plane->normal ); 
		plane->dist = plane4.w;
		return;
	default:
		memset (plane, 0, sizeof(*plane));
		plane->normal.x = 1;
		return;
	}
}
Ejemplo n.º 4
0
/*
=====================
CM_GenerateFacetFor3Points
=====================
*/
qboolean CM_GenerateFacetFor3Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
	// if we can't generate a valid plane for the points, ignore the facet
	if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
		f->numBoundaries = 0;
		return qfalse;
	}

	// make boundaries
	f->numBoundaries = 3;

	CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
	CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
	CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, a->xyz );

	VectorCopy( a->xyz, f->points[0] );
	VectorCopy( b->xyz, f->points[1] );
	VectorCopy( c->xyz, f->points[2] );

	TextureMatrixFromPoints( f, a, b, c );

	return qtrue;
}
Ejemplo n.º 5
0
static void ProjectDecalOntoWinding( decalProjector_t *dp, mapDrawSurface_t *ds, winding_t *w )
{
	int		i, j;
	float		d, d2, alpha;
	winding_t		*front, *back;
	mapDrawSurface_t	*ds2;
	bspDrawVert_t	*dv;
	vec4_t		plane;
	
	/* dummy check */
	if( w->numpoints < 3 )
	{
		FreeWinding( w );
		return;
	}
	
	/* offset by entity origin */
	for( i = 0; i < w->numpoints; i++ )
		VectorAdd( w->p[ i ], entityOrigin, w->p[ i ] );
	
	/* make a plane from the winding */
	if( !PlaneFromPoints( plane, w->p[ 0 ], w->p[ 1 ], w->p[ 2 ] ) )
	{
		FreeWinding( w );
		return;
	}
	
	/* backface check */
	d = DotProduct( dp->planes[ 0 ], plane );
	if( d < -0.0001f )
	{
		FreeWinding( w );
		return;
	}
	
	/* walk list of planes */
	for( i = 0; i < dp->numPlanes; i++ )
	{
		/* chop winding by the plane */
		ClipWindingEpsilon( w, dp->planes[ i ], dp->planes[ i ][ 3 ], 0.0625f, &front, &back );
		FreeWinding( w );
		
		/* lose the front fragment */
		if( front != NULL )
			FreeWinding( front );
		
		/* if nothing left in back, then bail */
		if( back == NULL )
			return;
		
		/* reset winding */
		w = back;
	}
	
	/* nothing left? */
	if( w == NULL || w->numpoints < 3 )
		return;
	
	/* add to counts */
	numDecalSurfaces++;
	
	/* make a new surface */
	ds2 = AllocDrawSurface( SURFACE_DECAL );
	
	/* set it up */
	ds2->entityNum = ds->entityNum;
	ds2->castShadows = ds->castShadows;
	ds2->recvShadows = ds->recvShadows;
	ds2->shaderInfo = dp->si;
	ds2->fogNum = ds->fogNum;	/* why was this -1? */
	ds2->lightmapScale = ds->lightmapScale;
	ds2->numVerts = w->numpoints;
	ds2->verts = Malloc( ds2->numVerts * sizeof( *ds2->verts ) );
	Mem_Set( ds2->verts, 0, ds2->numVerts * sizeof( *ds2->verts ) );
	
	/* set vertexes */
	for( i = 0; i < ds2->numVerts; i++ )
	{
		/* get vertex */
		dv = &ds2->verts[ i ];
		
		/* set alpha */
		d = DotProduct( w->p[ i ], dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ];
		d2 = DotProduct( w->p[ i ], dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ];
		alpha = 255.0f * d2 / (d + d2);
		if( alpha > 255 )
			alpha = 255;
		else if( alpha < 0 )
			alpha = 0;
		
		/* set misc */
		VectorSubtract( w->p[ i ], entityOrigin, dv->xyz );
		VectorCopy( plane, dv->normal );
		dv->st[ 0 ] = DotProduct( dv->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
		dv->st[ 1 ] = DotProduct( dv->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
		
		/* set color */
		for( j = 0; j < MAX_LIGHTMAPS; j++ )
		{
			dv->color[ j ][ 0 ] = 255;
			dv->color[ j ][ 1 ] = 255;
			dv->color[ j ][ 2 ] = 255;
			dv->color[ j ][ 3 ] = alpha;
		}
	}
}
Ejemplo n.º 6
0
/*
 * @brief
 */
static void ParseBrush(entity_t *mapent) {
	map_brush_t *b;
	int32_t i, j, k;
	side_t *side, *s2;
	int32_t plane_num;
	map_brush_texture_t td;
	vec3_t planepts[3];

	if (num_map_brushes == MAX_BSP_BRUSHES)
		Com_Error(ERR_FATAL, "MAX_BSP_BRUSHES\n");

	b = &map_brushes[num_map_brushes];
	b->original_sides = &map_brush_sides[num_map_brush_sides];
	b->entity_num = num_entities - 1;
	b->brush_num = num_map_brushes - mapent->first_brush;

	do {
		if (!GetToken(true))
			break;
		if (!g_strcmp0(token, "}"))
			break;

		if (num_map_brush_sides == MAX_BSP_BRUSH_SIDES)
			Com_Error(ERR_FATAL, "MAX_BSP_BRUSH_SIDES\n");
		side = &map_brush_sides[num_map_brush_sides];

		// read the three point plane definition
		for (i = 0; i < 3; i++) {
			if (i != 0)
				GetToken(true);
			if (g_strcmp0(token, "("))
				Com_Error(ERR_FATAL, "Parsing brush\n");

			for (j = 0; j < 3; j++) {
				GetToken(false);
				planepts[i][j] = atof(token);
			}

			GetToken(false);
			if (g_strcmp0(token, ")"))
				Com_Error(ERR_FATAL, "Parsing brush\n");
		}

		memset(&td, 0, sizeof(td));

		// read the texturedef
		GetToken(false);

		if (strlen(token) > sizeof(td.name) - 1)
			Com_Error(ERR_FATAL, "Texture name \"%s\" is too long.\n", token);

		g_strlcpy(td.name, token, sizeof(td.name));

		GetToken(false);
		td.shift[0] = atoi(token);
		GetToken(false);
		td.shift[1] = atoi(token);
		GetToken(false);
		td.rotate = atoi(token);
		GetToken(false);
		td.scale[0] = atof(token);
		GetToken(false);
		td.scale[1] = atof(token);

		if (TokenAvailable()) {
			GetToken(false);
			side->contents = atoi(token);
			GetToken(false);
			side->surf = td.flags = atoi(token);
			GetToken(false);
			td.value = atoi(token);
		} else {
			side->contents = CONTENTS_SOLID;
			side->surf = td.flags = 0;
			td.value = 0;
		}

		// resolve implicit surface and contents flags
		SetImpliedFlags(side, td.name);

		// translucent objects are automatically classified as detail
		if (side->surf & (SURF_ALPHA_TEST | SURF_BLEND_33 | SURF_BLEND_66))
			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYER_CLIP | CONTENTS_MONSTER_CLIP))
			side->contents |= CONTENTS_DETAIL;
		if (fulldetail)
			side->contents &= ~CONTENTS_DETAIL;
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS - 1) | CONTENTS_PLAYER_CLIP
				| CONTENTS_MONSTER_CLIP | CONTENTS_MIST)))
			side->contents |= CONTENTS_SOLID;

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT | SURF_SKIP)) {
			side->contents = 0;
			side->surf &= ~CONTENTS_DETAIL;
		}

		// find the plane number
		plane_num = PlaneFromPoints(planepts[0], planepts[1], planepts[2]);
		if (plane_num == -1) {
			Com_Verbose("Entity %i, Brush %i: plane with no normal\n", b->entity_num, b->brush_num);
			continue;
		}

		// see if the plane has been used already
		for (k = 0; k < b->num_sides; k++) {
			s2 = b->original_sides + k;
			if (s2->plane_num == plane_num) {
				Com_Verbose("Entity %i, Brush %i: duplicate plane\n", b->entity_num, b->brush_num);
				break;
			}
			if (s2->plane_num == (plane_num ^ 1)) {
				Com_Verbose("Entity %i, Brush %i: mirrored plane\n", b->entity_num, b->brush_num);
				break;
			}
		}
		if (k != b->num_sides)
			continue; // duplicated

		// keep this side
		side = b->original_sides + b->num_sides;
		side->plane_num = plane_num;
		side->texinfo = TexinfoForBrushTexture(&map_planes[plane_num], &td, vec3_origin);

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		map_brush_textures[num_map_brush_sides] = td;

		num_map_brush_sides++;
		b->num_sides++;
	} while (true);

	// get the content for the entire brush
	b->contents = BrushContents(b);

	// allow detail brushes to be removed
	if (nodetail && (b->contents & CONTENTS_DETAIL)) {
		b->num_sides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & MASK_LIQUID)) {
		b->num_sides = 0;
		return;
	}

	// create windings for sides and bounds for brush
	MakeBrushWindings(b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYER_CLIP | CONTENTS_MONSTER_CLIP)) {
		c_clip_brushes++;
		for (i = 0; i < b->num_sides; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity. After the entire entity is parsed,
	// the plane_nums and texinfos will be adjusted for
	// the origin brush
	if (b->contents & CONTENTS_ORIGIN) {
		char string[32];
		vec3_t origin;

		if (num_entities == 1) {
			Com_Error(ERR_FATAL,
					"Entity %i, Brush %i: origin brushes not allowed in world\n",
					b->entity_num, b->brush_num);
			return;
		}

		VectorAdd(b->mins, b->maxs, origin);
		VectorScale(origin, 0.5, origin);

		sprintf(string, "%i %i %i", (int32_t)origin[0], (int32_t)origin[1],
				(int32_t)origin[2]);
		SetKeyValue(&entities[b->entity_num], "origin", string);

		VectorCopy(origin, entities[b->entity_num].origin);

		// don't keep this brush
		b->num_sides = 0;

		return;
	}

	AddBrushBevels(b);

	num_map_brushes++;
	mapent->num_brushes++;
}
Ejemplo n.º 7
0
void ProcessDecals( void )
{
	int					i, j, x, y, pw[ 5 ], r, iterations, smoothNormals;
	float				distance, lightmapScale, backfaceAngle;
	vec4_t				projection, plane;
	vec3_t				origin, target, delta, lightmapAxis;
	vec3_t              minlight, minvertexlight, ambient, colormod;
	entity_t			*e, *e2;
	parseMesh_t			*p;
	mesh_t				*mesh, *subdivided;
	bspDrawVert_t		*dv[ 4 ];
	const char			*value;
	
	
	/* note it */
	Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" );

	/* no decals */
	if (nodecals)
	{
		for( i = 0; i < numEntities; i++ )
		{	
			/* get entity */
			e = &entities[ i ];
			value = ValueForKey( e, "classname" );
			if( Q_stricmp( value, "_decal" ) && Q_stricmp( value, "misc_decal" ) )
				continue;

			/* clear entity patches */
			e->patches = NULL; // fixme: LEAK!
		}
		return;
	}
	
	/* walk entity list */
	for( i = 0; i < numEntities; i++ )
	{
		/* get entity */
		e = &entities[ i ];
		value = ValueForKey( e, "classname" );
		if( Q_stricmp( value, "_decal" ) && Q_stricmp( value, "misc_decal" ) )
			continue;
		
		/* any patches? */
		if( e->patches == NULL )
		{
			Sys_Warning( e->mapEntityNum, "Decal entity without any patch meshes, ignoring." );
			e->epairs = NULL;	/* fixme: leak! */
			continue;
		}
		
		/* find target */
		value = ValueForKey( e, "target" );
		e2 = FindTargetEntity( value );
		
		/* no target? */
		if( e2 == NULL )
		{
			Sys_Warning( e->mapEntityNum, "Decal entity without a valid target, ignoring." );
			continue;
		}

		/* vortex: get lightmap scaling value for this entity */
		GetEntityLightmapScale( e, &lightmapScale, 0);

		/* vortex: get lightmap axis for this entity */
		GetEntityLightmapAxis( e, lightmapAxis, NULL );

		/* vortex: per-entity normal smoothing */
		GetEntityNormalSmoothing( e, &smoothNormals, 0);

		/* vortex: per-entity _minlight, _ambient, _color, _colormod */
		GetEntityMinlightAmbientColor( e, NULL, minlight, minvertexlight, ambient, colormod, qtrue );
		
		/* vortex: _backfacecull */
		if ( KeyExists(e, "_backfacecull") )
			backfaceAngle = FloatForKey(e, "_backfacecull");
		else if ( KeyExists(e, "_bfc") )
			backfaceAngle = FloatForKey(e, "_bfc");
		else
			backfaceAngle = 90.0f;

		/* walk entity patches */
		for( p = e->patches; p != NULL; p = e->patches )
		{
			/* setup projector */
			if( VectorCompare( e->origin, vec3_origin ) )
			{
				VectorAdd( p->eMins, p->eMaxs, origin );
				VectorScale( origin, 0.5f, origin );
			}
			else
				VectorCopy( e->origin, origin );
			
			VectorCopy( e2->origin, target );
			VectorSubtract( target, origin, delta );
			
			/* setup projection plane */
			distance = VectorNormalize( delta, projection );
			projection[ 3 ] = DotProduct( origin, projection );
			
			/* create projectors */
			if( distance > 0.125f )
			{
				/* tesselate the patch */
				iterations = IterationsForCurve( p->longestCurve, patchSubdivisions );
				subdivided = SubdivideMesh2( p->mesh, iterations );
				
				/* fit it to the curve and remove colinear verts on rows/columns */
				PutMeshOnCurve( *subdivided );
				mesh = RemoveLinearMeshColumnsRows( subdivided );
				FreeMesh( subdivided );
				
				/* offset by projector origin */
				for( j = 0; j < (mesh->width * mesh->height); j++ )
					VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz );
				
				/* iterate through the mesh quads */
				for( y = 0; y < (mesh->height - 1); y++ )
				{
					for( x = 0; x < (mesh->width - 1); x++ )
					{
						/* set indexes */
						pw[ 0 ] = x + (y * mesh->width);
						pw[ 1 ] = x + ((y + 1) * mesh->width);
						pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
						pw[ 3 ] = x + 1 + (y * mesh->width);
						pw[ 4 ] = x + (y * mesh->width);	/* same as pw[ 0 ] */
						
						/* set radix */
						r = (x + y) & 1;
						
						/* get drawverts */
						dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
						dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
						dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
						dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
						
						/* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */
						plane[ 0 ] = 0.0f;	/* stupid msvc */
						if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) && fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON )
						{
							/* make a quad projector */
							MakeDecalProjector( i, p->shaderInfo, projection, distance, 4, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals);
						}
						else
						{
							/* make first triangle */
							MakeDecalProjector( i, p->shaderInfo, projection, distance, 3, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals);
							
							/* make second triangle */
							dv[ 1 ] = dv[ 2 ];
							dv[ 2 ] = dv[ 3 ];
							MakeDecalProjector( i, p->shaderInfo, projection, distance, 3, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals);
						}
					}
				}
				
				/* clean up */
				free( mesh );
			}
			
			/* remove patch from entity (fixme: leak!) */
			e->patches = p->next;
			
			/* push patch to worldspawn (enable this to debug projectors) */
			#if 0
				p->next = entities[ 0 ].patches;
				entities[ 0 ].patches = p;
			#endif
		}
	}
	
	/* emit some stats */
	Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors );
}
Ejemplo n.º 8
0
void ProcessDecals( void )
{
	int			i, j, x, y, pw[ 5 ], r, iterations;
	float			distance;
	vec4_t			projection, plane;
	vec3_t			origin, target, delta;
	entity_t			*e, *e2;
	parseMesh_t		*p;
	mesh_t			*mesh, *subdivided;
	bspDrawVert_t		*dv[4];
	const char		*value;
	
	
	/* note it */
	MsgDev( D_NOTE, "--- ProcessDecals ---\n" );
	
	/* walk entity list */
	for( i = 0; i < numEntities; i++ )
	{
		/* get entity */
		e = &entities[ i ];
		value = ValueForKey( e, "classname" );
		if( com.stricmp( value, "_decal" ) )
			continue;
		
		/* any patches? */
		if( e->patches == NULL )
		{
			MsgDev( D_WARN, "Decal entity without any patch meshes, ignoring.\n" );
			e->epairs = NULL;	/* fixme: leak! */
			continue;
		}
		
		/* find target */
		value = ValueForKey( e, "target" );
		e2 = FindTargetEntity( value );
		
		/* no target? */
		if( e2 == NULL )
		{
			MsgDev( D_WARN, "Decal entity without a valid target, ignoring.\n" );
			continue;
		}
		
		/* walk entity patches */
		for( p = e->patches; p != NULL; p = e->patches )
		{
			/* setup projector */
			if( VectorCompare( e->origin, vec3_origin ) )
			{
				VectorAdd( p->eMins, p->eMaxs, origin );
				VectorScale( origin, 0.5f, origin );
			}
			else VectorCopy( e->origin, origin );
			
			VectorCopy( e2->origin, target );
			VectorSubtract( target, origin, delta );
			
			/* setup projection plane */
			distance = VectorNormalizeLength2( delta, projection );
			projection[ 3 ] = DotProduct( origin, projection );
			
			/* create projectors */
			if( distance > 0.125f )
			{
				/* tesselate the patch */
				iterations = IterationsForCurve( p->longestCurve, patch_subdivide->integer );
				subdivided = SubdivideMesh2( p->mesh, iterations );
				
				/* fit it to the curve and remove colinear verts on rows/columns */
				PutMeshOnCurve( *subdivided );
				mesh = RemoveLinearMeshColumnsRows( subdivided );
				FreeMesh( subdivided );
				
				/* offset by projector origin */
				for( j = 0; j < (mesh->width * mesh->height); j++ )
					VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz );
				
				/* iterate through the mesh quads */
				for( y = 0; y < (mesh->height - 1); y++ )
				{
					for( x = 0; x < (mesh->width - 1); x++ )
					{
						/* set indexes */
						pw[ 0 ] = x + (y * mesh->width);
						pw[ 1 ] = x + ((y + 1) * mesh->width);
						pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
						pw[ 3 ] = x + 1 + (y * mesh->width);
						pw[ 4 ] = x + (y * mesh->width);	/* same as pw[ 0 ] */
						
						/* set radix */
						r = (x + y) & 1;
						
						/* get drawverts */
						dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
						dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
						dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
						dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
						
						/* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */
						plane[ 0 ] = 0.0f;	/* stupid msvc */
						if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) &&
							fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON )
						{
							/* make a quad projector */
							MakeDecalProjector( p->shaderInfo, projection, distance, 4, dv );
						}
						else
						{
							/* make first triangle */
							MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );
							
							/* make second triangle */
							dv[ 1 ] = dv[ 2 ];
							dv[ 2 ] = dv[ 3 ];
							MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );
						}
					}
				}
				
				/* clean up */
				Mem_Free( mesh );
			}
			
			/* remove patch from entity (fixme: leak!) */
			e->patches = p->next;
			
			/* push patch to worldspawn (enable this to debug projectors) */
#if 0
			p->next = entities[ 0 ].patches;
			entities[ 0 ].patches = p;
#endif
		}
	}
	
	/* emit some stats */
	MsgDev( D_NOTE, "%9d decal projectors\n", numProjectors );
}
Ejemplo n.º 9
0
void RE_ProjectDecal( qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime,
                      int fadeTime )
{
	int              i;
	float            radius, iDist;
	vec3_t           xyz;
	vec4_t           omniProjection;
	decalVert_t      dv[ 4 ];
	decalProjector_t *dp, temp;

	/* first frame rendered does not have a valid decals list */
	if ( tr.refdef.decalProjectors == NULL )
	{
		return;
	}

	/* dummy check */
	if ( numPoints != 1 && numPoints != 3 && numPoints != 4 )
	{
		ri.Printf( PRINT_WARNING, "WARNING: Invalid number of decal points (%d)\n", numPoints );
		return;
	}

	/* early outs */
	if ( lifeTime == 0 )
	{
		return;
	}

	if ( projection[ 3 ] <= 0.0f )
	{
		return;
	}

	/* set times properly */
	if ( lifeTime < 0 || fadeTime < 0 )
	{
		lifeTime = 0;
		fadeTime = 0;
	}

	/* basic setup */
	temp.shader = R_GetShaderByHandle( hShader );  /* debug code */
	temp.numPlanes = temp.shader->entityMergable;
	temp.color[ 0 ] = color[ 0 ] * 255;
	temp.color[ 1 ] = color[ 1 ] * 255;
	temp.color[ 2 ] = color[ 2 ] * 255;
	temp.color[ 3 ] = color[ 3 ] * 255;
	temp.numPlanes = numPoints + 2;
	temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime;
	temp.fadeEndTime = temp.fadeStartTime + fadeTime;

	/* set up decal texcoords (fixme: support arbitrary projector st coordinates in trapcall) */
	dv[ 0 ].st[ 0 ] = 0.0f;
	dv[ 0 ].st[ 1 ] = 0.0f;
	dv[ 1 ].st[ 0 ] = 0.0f;
	dv[ 1 ].st[ 1 ] = 1.0f;
	dv[ 2 ].st[ 0 ] = 1.0f;
	dv[ 2 ].st[ 1 ] = 1.0f;
	dv[ 3 ].st[ 0 ] = 1.0f;
	dv[ 3 ].st[ 1 ] = 0.0f;

	/* omnidirectional? */
	if ( numPoints == 1 )
	{
		/* set up omnidirectional */
		numPoints = 4;
		temp.numPlanes = 6;
		temp.omnidirectional = qtrue;
		radius = projection[ 3 ];
		Vector4Set( omniProjection, 0.0f, 0.0f, -1.0f, radius * 2.0f );
		projection = omniProjection;
		iDist = 1.0f / ( radius * 2.0f );

		/* set corner */
		VectorSet( xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius );

		/* make x axis texture matrix (yz) */
		VectorSet( temp.texMat[ 0 ][ 0 ], 0.0f, iDist, 0.0f );
		temp.texMat[ 0 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 0 ][ 0 ], xyz );
		VectorSet( temp.texMat[ 0 ][ 1 ], 0.0f, 0.0f, iDist );
		temp.texMat[ 0 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 0 ][ 1 ], xyz );

		/* make y axis texture matrix (xz) */
		VectorSet( temp.texMat[ 1 ][ 0 ], iDist, 0.0f, 0.0f );
		temp.texMat[ 1 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 1 ][ 0 ], xyz );
		VectorSet( temp.texMat[ 1 ][ 1 ], 0.0f, 0.0f, iDist );
		temp.texMat[ 1 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 1 ][ 1 ], xyz );

		/* make z axis texture matrix (xy) */
		VectorSet( temp.texMat[ 2 ][ 0 ], iDist, 0.0f, 0.0f );
		temp.texMat[ 2 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 2 ][ 0 ], xyz );
		VectorSet( temp.texMat[ 2 ][ 1 ], 0.0f, iDist, 0.0f );
		temp.texMat[ 2 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 2 ][ 1 ], xyz );

		/* setup decal points */
		VectorSet( dv[ 0 ].xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius );
		VectorSet( dv[ 1 ].xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] + radius, points[ 0 ][ 2 ] + radius );
		VectorSet( dv[ 2 ].xyz, points[ 0 ][ 0 ] + radius, points[ 0 ][ 1 ] + radius, points[ 0 ][ 2 ] + radius );
		VectorSet( dv[ 3 ].xyz, points[ 0 ][ 0 ] + radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius );
	}
	else
	{
		/* set up unidirectional */
		temp.omnidirectional = qfalse;

		/* set up decal points */
		VectorCopy( points[ 0 ], dv[ 0 ].xyz );
		VectorCopy( points[ 1 ], dv[ 1 ].xyz );
		VectorCopy( points[ 2 ], dv[ 2 ].xyz );
		VectorCopy( points[ 3 ], dv[ 3 ].xyz );

		/* make texture matrix */
		if ( !MakeTextureMatrix( temp.texMat[ 0 ], projection, &dv[ 0 ], &dv[ 1 ], &dv[ 2 ] ) )
		{
			return;
		}
	}

	/* bound the projector */
	ClearBounds( temp.mins, temp.maxs );

	for ( i = 0; i < numPoints; i++ )
	{
		AddPointToBounds( dv[ i ].xyz, temp.mins, temp.maxs );
		VectorMA( dv[ i ].xyz, projection[ 3 ], projection, xyz );
		AddPointToBounds( xyz, temp.mins, temp.maxs );
	}

	/* make bounding sphere */
	VectorAdd( temp.mins, temp.maxs, temp.center );
	VectorScale( temp.center, 0.5f, temp.center );
	VectorSubtract( temp.maxs, temp.center, xyz );
	temp.radius = VectorLength( xyz );
	temp.radius2 = temp.radius * temp.radius;

	/* frustum cull the projector (fixme: this uses a stale frustum!) */
	if ( R_CullPointAndRadius( temp.center, temp.radius ) == CULL_OUT )
	{
		return;
	}

	/* make the front plane */
	if ( !PlaneFromPoints( temp.planes[ 0 ], dv[ 0 ].xyz, dv[ 1 ].xyz, dv[ 2 ].xyz ) )
	{
		return;
	}

	/* make the back plane */
	VectorSubtract( vec3_origin, temp.planes[ 0 ], temp.planes[ 1 ] );
	VectorMA( dv[ 0 ].xyz, projection[ 3 ], projection, xyz );
	temp.planes[ 1 ][ 3 ] = DotProduct( xyz, temp.planes[ 1 ] );

	/* make the side planes */
	for ( i = 0; i < numPoints; i++ )
	{
		VectorMA( dv[ i ].xyz, projection[ 3 ], projection, xyz );

		if ( !PlaneFromPoints( temp.planes[ i + 2 ], dv[( i + 1 ) % numPoints ].xyz, dv[ i ].xyz, xyz ) )
		{
			return;
		}
	}

	/* create a new projector */
	dp = &tr.refdef.decalProjectors[ r_numDecalProjectors & DECAL_PROJECTOR_MASK ];
	Com_Memcpy( dp, &temp, sizeof( *dp ) );

	/* we have a winner */
	r_numDecalProjectors++;
}
Ejemplo n.º 10
0
void MakeDecimatedMap(int *NumNodes, int *NumTris, NODE **pNode, TRI **pTri)
{
	int  compare(TRITABLE *, TRITABLE *);
	int Bisect(NODE *, int, int, int);
	void CalcAngles(NODE *, int *, float *);
	void EdgeOnSide(int *, int *, int *);
	int tricall(int, NODE *, int *, TRI **, TRI **, const char *);
	int CheckBorders(int *,int,NODE *,int *,TRI **);

	float       biggesterror;
	int         i, j, N;
	int         j0, j1, j2;
	int         NumNodesToSave;
	int         NumNodesUsed;
	NODE        *Node;
	TRI         *Tri;
	TRITABLE    *TriTable;

	if(Decimate <= 0) return;
        /*
	ghCursorCurrent = LoadCursor(NULL,IDC_WAIT);
	SetCursor(ghCursorCurrent);
        */
	dh = (Hur-Hll)/NH;
	dv = (Vur-Vll)/NV;
	NVP1 = NV+1;

	NumNodes[0] = (NH+1)*(NVP1);
	*pNode = (NODE *) malloc(NumNodes[0] * sizeof(NODE));
	Node = *pNode;
	memset(Node,0,NumNodes[0]*sizeof(NODE));

	// Copy [NH][NV] vertex array to our working node array
	for(i=0,N=0; i<=NH; i++)
	{
		for(j=0; j<=NV; j++, N++)
		{
			Node[N].p[0]  = (float)xyz[i][j].p[0];
			Node[N].p[1]  = (float)xyz[i][j].p[1];
			Node[N].p[2]  = (float)xyz[i][j].p[2];
			Node[N].fixed = xyz[i][j].fixed;
		}
	}
	// Start things off with the corner values
	Node[ 0].used           = 1;
	Node[NV].used           = 1;
	Node[NH*NVP1].used    = 1;
	Node[NH*NVP1+NV].used = 1;
	NumNodesUsed = 4;
	tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY");
	Tri = *pTri;

	// Which coordinates are we triangulating on?
	switch(Plane)
	{
	case PLANE_XZ0:
	case PLANE_XZ1:
		j0 = 1;
		j1 = 0;
		j2 = 2;
		break;
	case PLANE_YZ0:
	case PLANE_YZ1:
		j0 = 0;
		j1 = 1;
		j2 = 2;
		break;
	default:
		j0 = 2;
		j1 = 0;
		j2 = 1;
	}

	// TriTable stores the largest error in a triangle and the node where that
	// error occurs
	TriTable = (TRITABLE *) malloc(NH*NV*2 * sizeof(TRITABLE));
	NumNodesToSave = min(NumNodes[0], (int)(0.01*(100-Decimate)*(NumNodes[0]-NumNodesUsed)+NumNodesUsed));

	while(NumNodesUsed < NumNodesToSave)
	{
		for(i=0; i<NumTris[0]; i++)
			Tri[i].flag = 0;

		// For every node that's not currently used, find what triangle it
		// lies on, and the error at this node
		for(i=0, biggesterror=0; i<NumNodes[0]; i++)
		{
			if(Node[i].used) continue;
			for(j=0, Node[i].tri=-1; (j<NumTris[0]) && (Node[i].tri==-1); j++)
			{
				if( side(Node[i].p[j1],          Node[i].p[j2],
					     Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2],
					     Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2]) < 0. ) continue;
				if( side(Node[i].p[j1],          Node[i].p[j2],
					     Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2],
					     Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2]) < 0. ) continue;
				if( side(Node[i].p[j1],          Node[i].p[j2],
					     Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2],
					     Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2]) < 0. ) continue;
				Node[i].tri = j;
			}
			if(Node[i].tri < 0)
			{
                          /*
				ghCursorCurrent = ghCursorDefault;
				SetCursor(ghCursorCurrent);
                          */
				g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,
					"Error: Couldn't find the triangle bounding a point.",
					"Decimation Error",MB_ICONEXCLAMATION, NULL);
				return;
			}
			if(!Tri[Node[i].tri].flag)
			{
				PlaneFromPoints(Node[Tri[Node[i].tri].v[0]].p,
				                Node[Tri[Node[i].tri].v[1]].p,
				                Node[Tri[Node[i].tri].v[2]].p,
								&Tri[Node[i].tri].plane);
				Tri[Node[i].tri].flag = 1;
			}
			Node[i].error =
				Node[i].p[j0] - (Tri[Node[i].tri].plane.dist -
							     Tri[Node[i].tri].plane.normal[j1]*Node[i].p[j1] -
								 Tri[Node[i].tri].plane.normal[j2]*Node[i].p[j2]  )/
								 Tri[Node[i].tri].plane.normal[j0];
			biggesterror = max(biggesterror,Absolute(Node[i].error));
		}
		if(biggesterror == 0)
			NumNodesToSave = NumNodesUsed;
		else
		{
			// For all current triangles, build a list of worst-case nodes
			memset(TriTable,0,NH*NV*2*sizeof(TRITABLE));
			for(i=0; i<NumNodes[0]; i++)
			{
				if(Node[i].used) continue;
				if(Absolute(Node[i].error) > TriTable[Node[i].tri].error)
				{
					TriTable[Node[i].tri].error = (float)(Absolute(Node[i].error));
					TriTable[Node[i].tri].node  = i;
				}
			}
			qsort( (void *)TriTable, (size_t)(NumTris[0]), sizeof(TRITABLE), (int (*)(const void *, const void *))compare );
			for(i=0; i<NumTris[0] && NumNodesUsed < NumNodesToSave && TriTable[i].error > 0.5*biggesterror; i++)
			{
				if(Node[TriTable[i].node].used) continue;  // shouldn't happen
				NumNodesUsed++;
				Node[TriTable[i].node].used++;
			}
			free(Tri);
			tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY");
			Tri = *pTri;
			// Sliver-check along borders. Since borders are often linear, the errors
			// along borders will often be zero, so no new points will be added. This
			// tends to produce long, thin brushes. For all border triangles, check
			// that minimum angle isn't less than SLIVER_ANGLE. If it is, add another
			// vertex.
			while(CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri) > 0)
			{
			}
			Tri = *pTri;
		}
	}
	free(TriTable);
	// One last time (because we're pessimistic), check border triangles
//	CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri);
//	Tri = *pTri;

	// Check that all fixed points are exact. If not, add them to the mix.
	// First check to see if we have any fixed points that aren't already used.
	for(i=0, N=0; i<NumNodes[0] && !N; i++)
	{
		if(Node[i].used) continue;
		if(Node[i].fixed) N++;
	}
	if(N)
	{
		// Zero out the flag member of all triangles, indicating that
		// the plane equation has not been found.
		for(i=0; i<NumTris[0]; i++)
			Tri[i].flag = 0;

		for(i=0; i<NumNodes[0]; i++)
		{
			if(Node[i].used) continue;
			if(!Node[i].fixed) continue;
			Node[i].tri = -1;
			for(j=0; j<NumTris[0] && Node[i].tri==-1; j++)
			{
				if( side(Node[i].p[j1],          Node[i].p[j2],
					Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2],
					Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2]) < 0. ) continue;
				if( side(Node[i].p[j1],          Node[i].p[j2],
					Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2],
					Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2]) < 0. ) continue;
				if( side(Node[i].p[j1],          Node[i].p[j2],
					Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2],
					Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2]) < 0. ) continue;
				Node[i].tri = j;
			}
			if(Node[i].tri < 0)
			{
                          /*
				ghCursorCurrent = ghCursorDefault;
				SetCursor(ghCursorCurrent);
                          */
				g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,
					"Error: Couldn't find the triangle bounding a point.",
					"Decimation Error",MB_ICONEXCLAMATION, NULL);
				return;
			}
			if(!Tri[Node[i].tri].flag)
			{
				PlaneFromPoints(Node[Tri[Node[i].tri].v[0]].p,
					            Node[Tri[Node[i].tri].v[1]].p,
				                Node[Tri[Node[i].tri].v[2]].p,
				                &Tri[Node[i].tri].plane);
				Tri[Node[i].tri].flag = 1;
			}
			Node[i].error =
				Node[i].p[j0] - (Tri[Node[i].tri].plane.dist -
				Tri[Node[i].tri].plane.normal[j1]*Node[i].p[j1] -
				Tri[Node[i].tri].plane.normal[j2]*Node[i].p[j2]  )/
				Tri[Node[i].tri].plane.normal[j0];
			if(Absolute(Node[i].error) > 0.5)
			{
				NumNodesUsed++;
				Node[i].used++;
				free(Tri);
				tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY");
				Tri = *pTri;
			}
		}
	}

	// Swap node orders for surfaces facing down, north or west so that
	// they are counterclockwise when facing the surface

	if((Plane == PLANE_XY1) || (Plane == PLANE_XZ0) || (Plane == PLANE_YZ1) )
	{
		for(i=0; i<NumTris[0]; i++)
		{
			j = Tri[i].v[1];
			Tri[i].v[1] = Tri[i].v[2];
			Tri[i].v[2] = j;
		}
	}

	// Store bounding box coords
	for(i=0; i<NumTris[0]; i++)
	{
		Tri[i].min[0] =                   Node[Tri[i].v[0]].p[0];
		Tri[i].min[0] = min(Tri[i].min[0],Node[Tri[i].v[1]].p[0]);
		Tri[i].min[0] = min(Tri[i].min[0],Node[Tri[i].v[2]].p[0]);
		Tri[i].min[1] =                   Node[Tri[i].v[0]].p[1];
		Tri[i].min[1] = min(Tri[i].min[1],Node[Tri[i].v[1]].p[1]);
		Tri[i].min[1] = min(Tri[i].min[1],Node[Tri[i].v[2]].p[1]);
		Tri[i].min[2] =                   Node[Tri[i].v[0]].p[2];
		Tri[i].min[2] = min(Tri[i].min[2],Node[Tri[i].v[1]].p[2]);
		Tri[i].min[2] = min(Tri[i].min[2],Node[Tri[i].v[2]].p[2]);
		Tri[i].max[0] =                   Node[Tri[i].v[0]].p[0];
		Tri[i].max[0] = max(Tri[i].max[0],Node[Tri[i].v[1]].p[0]);
		Tri[i].max[0] = max(Tri[i].max[0],Node[Tri[i].v[2]].p[0]);
		Tri[i].max[1] =                   Node[Tri[i].v[0]].p[1];
		Tri[i].max[1] = max(Tri[i].max[1],Node[Tri[i].v[1]].p[1]);
		Tri[i].max[1] = max(Tri[i].max[1],Node[Tri[i].v[2]].p[1]);
		Tri[i].max[2] =                   Node[Tri[i].v[0]].p[2];
		Tri[i].max[2] = max(Tri[i].max[2],Node[Tri[i].v[1]].p[2]);
		Tri[i].max[2] = max(Tri[i].max[2],Node[Tri[i].v[2]].p[2]);
	}
        /*
	ghCursorCurrent = ghCursorDefault;
	SetCursor(ghCursorCurrent);
        */
}
Ejemplo n.º 11
0
/*
* R_AddPortalSurface
*/
portalSurface_t *R_AddPortalSurface( const entity_t *ent, const mesh_t *mesh, 
	const vec3_t mins, const vec3_t maxs, const shader_t *shader )
{
	unsigned int i;
	float dist;
	cplane_t plane, untransformed_plane;
	vec3_t v[3];
	portalSurface_t *portalSurface;

	if( !mesh ) {
		return NULL;
	}

	if( R_FASTSKY() && !( shader->flags & (SHADER_PORTAL_CAPTURE|SHADER_PORTAL_CAPTURE2) ) ) {
		// r_fastsky doesn't affect portalmaps
		return NULL;
	}

	for( i = 0; i < 3; i++ ) {
		VectorCopy( mesh->xyzArray[mesh->elems[i]], v[i] );
	}

	PlaneFromPoints( v, &untransformed_plane );
	untransformed_plane.dist += DotProduct( ent->origin, untransformed_plane.normal );
	CategorizePlane( &untransformed_plane );

	if( shader->flags & SHADER_AUTOSPRITE )
	{
		vec3_t centre;

		// autosprites are quads, facing the viewer
		if( mesh->numVerts < 4 ) {
			return NULL;
		}

		// compute centre as average of 4 vertices
		VectorCopy( mesh->xyzArray[mesh->elems[3]], centre );
		for( i = 0; i < 3; i++ )
			VectorAdd( centre, v[i], centre );
		VectorMA( ent->origin, 0.25, centre, centre );

		VectorNegate( &rn.viewAxis[AXIS_FORWARD], plane.normal );
		plane.dist = DotProduct( plane.normal, centre );
		CategorizePlane( &plane );
	}
	else
	{
		vec3_t temp;
		mat3_t entity_rotation;

		// regular surfaces
		if( !Matrix3_Compare( ent->axis, axis_identity ) )
		{
			Matrix3_Transpose( ent->axis, entity_rotation );

			for( i = 0; i < 3; i++ ) {
				VectorCopy( v[i], temp );
				Matrix3_TransformVector( entity_rotation, temp, v[i] ); 
				VectorMA( ent->origin, ent->scale, v[i], v[i] );
			}

			PlaneFromPoints( v, &plane );
			CategorizePlane( &plane );
		}
		else
		{
			plane = untransformed_plane;
		}
	}

	if( ( dist = PlaneDiff( rn.viewOrigin, &plane ) ) <= BACKFACE_EPSILON )
	{
		// behind the portal plane
		if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) {
			return NULL;
		}

		// we need to render the backplane view
	}

	// check if portal view is opaque due to alphagen portal
	if( shader->portalDistance && dist > shader->portalDistance ) {
		return NULL;
	}

	// find the matching portal plane
	for( i = 0; i < rn.numPortalSurfaces; i++ ) {
		portalSurface = &rn.portalSurfaces[i];

		if( portalSurface->entity == ent &&
			portalSurface->shader == shader &&
			DotProduct( portalSurface->plane.normal, plane.normal ) > 0.99f &&
			fabs( portalSurface->plane.dist - plane.dist ) < 0.1f ) {
				goto addsurface;
		}
	}

	if( i == MAX_PORTAL_SURFACES ) {
		// not enough space
		return NULL;
	}

	portalSurface = &rn.portalSurfaces[rn.numPortalSurfaces++];
	portalSurface->entity = ent;
	portalSurface->plane = plane;
	portalSurface->shader = shader;
	portalSurface->untransformed_plane = untransformed_plane;
	ClearBounds( portalSurface->mins, portalSurface->maxs );
	memset( portalSurface->texures, 0, sizeof( portalSurface->texures ) );

addsurface:
	AddPointToBounds( mins, portalSurface->mins, portalSurface->maxs );
	AddPointToBounds( maxs, portalSurface->mins, portalSurface->maxs );
	VectorAdd( portalSurface->mins, portalSurface->maxs, portalSurface->centre );
	VectorScale( portalSurface->centre, 0.5, portalSurface->centre );

	return portalSurface;
}
Ejemplo n.º 12
0
static void FilterTraceWindingIntoNodes_r(traceWinding_t * tw, int nodeNum)
{
	int             num;
	vec4_t          plane1, plane2, reverse;
	traceNode_t    *node;
	traceWinding_t  front, back;


	/* don't filter if passed a bogus node (solid, etc) */
	if(nodeNum < 0 || nodeNum >= numTraceNodes)
		return;

	/* get node */
	node = &traceNodes[nodeNum];

	/* is this a decision node? */
	if(node->type >= 0)
	{
		/* create winding plane if necessary, filtering out bogus windings as well */
		if(nodeNum == headNodeNum)
		{
			if(!PlaneFromPoints(tw->plane, tw->v[0].xyz, tw->v[1].xyz, tw->v[2].xyz, qtrue))
				return;
		}

		/* validate the node */
		if(node->children[0] == 0 || node->children[1] == 0)
			Error("Invalid tracenode: %d", nodeNum);

		/* get node plane */
		Vector4Copy(node->plane, plane1);

		/* get winding plane */
		Vector4Copy(tw->plane, plane2);

		/* invert surface plane */
		VectorSubtract(vec3_origin, plane2, reverse);
		reverse[3] = -plane2[3];

		/* front only */
		if(DotProduct(plane1, plane2) > 0.999f && fabs(plane1[3] - plane2[3]) < 0.001f)
		{
			FilterTraceWindingIntoNodes_r(tw, node->children[0]);
			return;
		}

		/* back only */
		if(DotProduct(plane1, reverse) > 0.999f && fabs(plane1[3] - reverse[3]) < 0.001f)
		{
			FilterTraceWindingIntoNodes_r(tw, node->children[1]);
			return;
		}

		/* clip the winding by node plane */
		ClipTraceWinding(tw, plane1, &front, &back);

		/* filter by node plane */
		if(front.numVerts >= 3)
			FilterTraceWindingIntoNodes_r(&front, node->children[0]);
		if(back.numVerts >= 3)
			FilterTraceWindingIntoNodes_r(&back, node->children[1]);

		/* return to caller */
		return;
	}

	/* add winding to leaf node */
	num = AddTraceWinding(tw);
	AddItemToTraceNode(node, num);
}
Ejemplo n.º 13
0
int FindMetaTriangle( metaTriangle_t *src, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c, int planeNum ){
	int triIndex;
	vec3_t dir;



	/* detect degenerate triangles fixme: do something proper here */
	VectorSubtract( a->xyz, b->xyz, dir );
	if ( VectorLength( dir ) < 0.125f ) {
		return -1;
	}
	VectorSubtract( b->xyz, c->xyz, dir );
	if ( VectorLength( dir ) < 0.125f ) {
		return -1;
	}
	VectorSubtract( c->xyz, a->xyz, dir );
	if ( VectorLength( dir ) < 0.125f ) {
		return -1;
	}

	/* find plane */
	if ( planeNum >= 0 ) {
		/* because of precision issues with small triangles, try to use the specified plane */
		src->planeNum = planeNum;
		VectorCopy( mapplanes[ planeNum ].normal, src->plane );
		src->plane[ 3 ] = mapplanes[ planeNum ].dist;
	}
	else
	{
		/* calculate a plane from the triangle's points (and bail if a plane can't be constructed) */
		src->planeNum = -1;
		if ( PlaneFromPoints( src->plane, a->xyz, b->xyz, c->xyz ) == qfalse ) {
			return -1;
		}
	}

	/* ydnar 2002-10-03: repair any bogus normals (busted ase import kludge) */
	if ( VectorLength( a->normal ) <= 0.0f ) {
		VectorCopy( src->plane, a->normal );
	}
	if ( VectorLength( b->normal ) <= 0.0f ) {
		VectorCopy( src->plane, b->normal );
	}
	if ( VectorLength( c->normal ) <= 0.0f ) {
		VectorCopy( src->plane, c->normal );
	}

	/* ydnar 2002-10-04: set lightmap axis if not already set */
	if ( !( src->si->compileFlags & C_VERTEXLIT ) &&
		 src->lightmapAxis[ 0 ] == 0.0f && src->lightmapAxis[ 1 ] == 0.0f && src->lightmapAxis[ 2 ] == 0.0f ) {
		/* the shader can specify an explicit lightmap axis */
		if ( src->si->lightmapAxis[ 0 ] || src->si->lightmapAxis[ 1 ] || src->si->lightmapAxis[ 2 ] ) {
			VectorCopy( src->si->lightmapAxis, src->lightmapAxis );
		}

		/* new axis-finding code */
		else{
			CalcLightmapAxis( src->plane, src->lightmapAxis );
		}
	}

	/* fill out the src triangle */
	src->indexes[ 0 ] = FindMetaVertex( a );
	src->indexes[ 1 ] = FindMetaVertex( b );
	src->indexes[ 2 ] = FindMetaVertex( c );

	/* try to find an existing triangle */
	#ifdef USE_EXHAUSTIVE_SEARCH
	{
		int i;
		metaTriangle_t  *tri;


		for ( i = 0, tri = metaTriangles; i < numMetaTriangles; i++, tri++ )
		{
			if ( memcmp( src, tri, sizeof( metaTriangle_t ) ) == 0 ) {
				return i;
			}
		}
	}
	#endif

	/* get a new triangle */
	triIndex = AddMetaTriangle();

	/* add the triangle */
	memcpy( &metaTriangles[ triIndex ], src, sizeof( metaTriangle_t ) );

	/* return the triangle index */
	return triIndex;
}
Ejemplo n.º 14
0
/*
===========
MakeBrushPlanes
===========
*/
qboolean MakeBrushPlanes (brush_t *b)
{
    int		i, j;
    int		planenum;
    side_t	*s;
    int		contents;
    bface_t	*f;
    vec3_t	origin;

    //
    // if the origin key is set (by an origin brush), offset all of the values
    //
    GetVectorForKey (&entities[b->entitynum], "origin", origin);

    //
    // convert to mapplanes
    //
    for (i=0 ; i<b->numsides ; i++)
    {
        s = &brushsides[b->firstside + i];
        for (j=0 ; j<3 ; j++)
        {
            VectorSubtract (s->planepts[j], origin, s->planepts[j]);
        }
        planenum = PlaneFromPoints (s->planepts[0], s->planepts[1], s->planepts[2]);
        if (planenum == -1)
        {
            printf ("Entity %i, Brush %i: plane with no normal\n"
                    , b->entitynum, b->brushnum);
            continue;
        }

        //
        // see if the plane has been used already
        //
        for (f=b->hulls[0].faces ; f ; f=f->next)
        {
            if (f->planenum == planenum || f->planenum == (planenum^1) )
            {
                char *pszClass = "Unknown Class";
                if ( b->entitynum )
                {
                    entity_t	*e = entities + b->entitynum;
                    pszClass = ValueForKey(e, "classname" );
                }

                printf( "Entity %i, Brush %i: A '%s' @(%.0f,%.0f,%.0f) has a coplanar plane at (%.0f, %.0f, %.0f), texture %s\n",
                        b->entitynum, b->brushnum, pszClass, origin[0], origin[1], origin[2], s->planepts[0][0]+origin[0], s->planepts[0][1]+origin[1], s->planepts[0][2]+origin[2], s->td.name );
                return false;
            }
        }

        f = malloc(sizeof(*f));
        memset (f, 0, sizeof(*f));

        f->planenum = planenum;
        f->plane = &mapplanes[planenum];
        f->next = b->hulls[0].faces;
        b->hulls[0].faces = f;
        f->texinfo = onlyents ? 0 : TexinfoForBrushTexture (f->plane, &s->td, origin);
    }

    return true;
}
Ejemplo n.º 15
0
//	projects decal onto a polygon
void ProjectDecalOntoWinding( decalProjector_t* dp, int numPoints, vec3_t points[ 2 ][ MAX_DECAL_VERTS ],
	const idWorldSurface* surf, mbrush46_model_t* bmodel ) {
	//	make a plane from the winding
	vec4_t plane;
	if ( !PlaneFromPoints( plane, points[ 0 ][ 0 ], points[ 0 ][ 1 ], points[ 0 ][ 2 ] ) ) {
		return;
	}

	//	omnidirectional projectors need plane type
	float pd;
	int axis;
	float alpha = 1.f;
	if ( dp->omnidirectional ) {
		pd = 1.0f;

		//	fade by distance from plane
		float d = DotProduct( dp->center, plane ) - plane[ 3 ];
		alpha = 1.0f - ( fabs( d ) / dp->radius );
		if ( alpha < 0.0f ) {
			return;
		}
		if ( alpha > 1.0f ) {
			alpha = 1.0f;
		}

		//	set projection axis
		vec3_t absNormal;
		absNormal[ 0 ] = fabs( plane[ 0 ] );
		absNormal[ 1 ] = fabs( plane[ 1 ] );
		absNormal[ 2 ] = fabs( plane[ 2 ] );
		if ( absNormal[ 2 ] >= absNormal[ 0 ] && absNormal[ 2 ] >= absNormal[ 1 ] ) {
			axis = 2;
		} else if ( absNormal[ 0 ] >= absNormal[ 1 ] && absNormal[ 0 ] >= absNormal[ 2 ] ) {
			axis = 0;
		} else {
			axis = 1;
		}
	} else {
		//	backface check
		pd = DotProduct( dp->planes[ 0 ], plane );
		if ( pd < -0.0001f ) {
			return;
		}

		//	directional decals use first texture matrix
		axis = 0;
	}

	//	chop the winding by all the projector planes
	int pingPong = 0;
	for ( int i = 0; i < dp->numPlanes; i++ ) {
		ChopWindingBehindPlane( numPoints, points[ pingPong ], &numPoints, points[ !pingPong ], dp->planes[ i ], 0.0f );
		pingPong ^= 1;
		if ( numPoints < 3 ) {
			return;
		}
		if ( numPoints == MAX_DECAL_VERTS ) {
			break;
		}
	}

	//	find first free decal (fixme: optimize this)
	int count = ( bmodel == tr.world->bmodels ? MAX_WORLD_DECALS : MAX_ENTITY_DECALS );
	mbrush46_decal_t* oldest = &bmodel->decals[ 0 ];
	mbrush46_decal_t* decal = bmodel->decals;
	int i;
	for ( i = 0; i < count; i++, decal++ ) {
		//	try to find an empty decal slot
		if ( decal->shader == NULL ) {
			break;
		}

		//	find oldest decal
		if ( decal->fadeEndTime < oldest->fadeEndTime ) {
			oldest = decal;
		}
	}

	//	guess we have to use the oldest decal
	if ( i >= count ) {
		decal = oldest;
	}

	//	r_speeds useful info
	tr.pc.c_decalSurfacesCreated++;

	//	set it up (fixme: get the shader before this happens)
	decal->parent = surf;
	decal->shader = dp->shader;
	decal->fadeStartTime = dp->fadeStartTime;
	decal->fadeEndTime = dp->fadeEndTime;
	decal->fogIndex = surf->fogIndex;

	//	add points
	decal->numVerts = numPoints;
	polyVert_t* vert = decal->verts;
	for ( i = 0; i < numPoints; i++, vert++ ) {
		//	set xyz
		VectorCopy( points[ pingPong ][ i ], vert->xyz );

		//	set st
		vert->st[ 0 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 0 ] ) + dp->texMat[ axis ][ 0 ][ 3 ];
		vert->st[ 1 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 1 ] ) + dp->texMat[ axis ][ 1 ][ 3 ];

		//	unidirectional decals fade by half distance from front->back planes
		if ( !dp->omnidirectional ) {
			//	set alpha
			float d = DotProduct( vert->xyz, dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ];
			float d2 = DotProduct( vert->xyz, dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ];
			alpha = 2.0f * d2 / ( d + d2 );
			if ( alpha > 1.0f ) {
				alpha = 1.0f;
			} else if ( alpha < 0.0f ) {
				alpha = 0.0f;
			}
		}

		//	set color
		vert->modulate[ 0 ] = idMath::FtoiFast( pd * alpha * dp->color[ 0 ] );
		vert->modulate[ 1 ] = idMath::FtoiFast( pd * alpha * dp->color[ 1 ] );
		vert->modulate[ 2 ] = idMath::FtoiFast( pd * alpha * dp->color[ 2 ] );
		vert->modulate[ 3 ] = idMath::FtoiFast( alpha * dp->color[ 3 ] );
	}
}
Ejemplo n.º 16
0
/*
* R_UpdatePortalSurface
*/
void R_UpdatePortalSurface( portalSurface_t *portalSurface, const mesh_t *mesh,
	const vec3_t mins, const vec3_t maxs, const shader_t *shader ) {
	unsigned int i;
	float dist;
	cplane_t plane, untransformed_plane;
	vec3_t v[3];
	const entity_t *ent;

	if( !mesh || !portalSurface ) {
		return;
	}

	ent = portalSurface->entity;

	for( i = 0; i < 3; i++ ) {
		VectorCopy( mesh->xyzArray[mesh->elems[i]], v[i] );
	}

	PlaneFromPoints( v, &untransformed_plane );
	untransformed_plane.dist += DotProduct( ent->origin, untransformed_plane.normal );
	untransformed_plane.dist += 1; // nudge along the normal a bit
	CategorizePlane( &untransformed_plane );

	if( shader->flags & SHADER_AUTOSPRITE ) {
		vec3_t centre;

		// autosprites are quads, facing the viewer
		if( mesh->numVerts < 4 ) {
			return;
		}

		// compute centre as average of 4 vertices
		VectorCopy( mesh->xyzArray[mesh->elems[3]], centre );
		for( i = 0; i < 3; i++ )
			VectorAdd( centre, v[i], centre );
		VectorMA( ent->origin, 0.25, centre, centre );

		VectorNegate( &rn.viewAxis[AXIS_FORWARD], plane.normal );
		plane.dist = DotProduct( plane.normal, centre );
		CategorizePlane( &plane );
	} else {
		vec3_t temp;
		mat3_t entity_rotation;

		// regular surfaces
		if( !Matrix3_Compare( ent->axis, axis_identity ) ) {
			Matrix3_Transpose( ent->axis, entity_rotation );

			for( i = 0; i < 3; i++ ) {
				VectorCopy( v[i], temp );
				Matrix3_TransformVector( entity_rotation, temp, v[i] );
				VectorMA( ent->origin, ent->scale, v[i], v[i] );
			}

			PlaneFromPoints( v, &plane );
			CategorizePlane( &plane );
		} else {
			plane = untransformed_plane;
		}
	}

	if( ( dist = PlaneDiff( rn.viewOrigin, &plane ) ) <= BACKFACE_EPSILON ) {
		// behind the portal plane
		if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) {
			return;
		}

		// we need to render the backplane view
	}

	// check if portal view is opaque due to alphagen portal
	if( shader->portalDistance && dist > shader->portalDistance ) {
		return;
	}

	portalSurface->plane = plane;
	portalSurface->untransformed_plane = untransformed_plane;

	AddPointToBounds( mins, portalSurface->mins, portalSurface->maxs );
	AddPointToBounds( maxs, portalSurface->mins, portalSurface->maxs );
	VectorAdd( portalSurface->mins, portalSurface->maxs, portalSurface->centre );
	VectorScale( portalSurface->centre, 0.5, portalSurface->centre );
}
Ejemplo n.º 17
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);
				}
			}
		}
	}
}
Ejemplo n.º 18
0
void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw )
{
    int                    i, x, y, v, t, pw[ 5 ], r;
    bspDrawSurface_t    *ds;
    surfaceInfo_t        *info;
    bspDrawVert_t        *bogus;
    bspDrawVert_t        *dv[ 4 ];
    mesh_t                src, *subdivided, *mesh;
    float                *radVertexLuxel;
    float                dist;
    vec4_t                plane;
    qboolean            planar;
    radWinding_t        rw;
    
    
    /* get surface */
    ds = &bspDrawSurfaces[ num ];
    info = &surfaceInfos[ num ];
    
    /* construct a bogus vert list with color index stuffed into color[ 0 ] */
    bogus = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) );
    memcpy( bogus, &yDrawVerts[ ds->firstVert ], ds->numVerts * sizeof( bspDrawVert_t ) );
    for( i = 0; i < ds->numVerts; i++ )
        bogus[ i ].color[ 0 ][ 0 ] = i;
    
    /* build a subdivided mesh identical to shadow facets for this patch */
    /* this MUST MATCH FacetsForPatch() identically! */
    src.width = ds->patchWidth;
    src.height = ds->patchHeight;
    src.verts = bogus;
    //%    subdivided = SubdivideMesh( src, 8, 512 );
    subdivided = SubdivideMesh2( src, info->patchIterations );
    PutMeshOnCurve( *subdivided );
    //%    MakeMeshNormals( *subdivided );
    mesh = RemoveLinearMeshColumnsRows( subdivided );
    FreeMesh( subdivided );
    free( bogus );
    
    /* FIXME: build interpolation table into color[ 1 ] */
    
    /* fix up color indexes */
    for( i = 0; i < (mesh->width * mesh->height); i++ )
    {
        dv[ 0 ] = &mesh->verts[ i ];
        if( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts )
            dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1;
    }
    
    /* iterate through the mesh quads */
    for( y = 0; y < (mesh->height - 1); y++ )
    {
        for( x = 0; x < (mesh->width - 1); x++ )
        {
            /* set indexes */
            pw[ 0 ] = x + (y * mesh->width);
            pw[ 1 ] = x + ((y + 1) * mesh->width);
            pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
            pw[ 3 ] = x + 1 + (y * mesh->width);
            pw[ 4 ] = x + (y * mesh->width);    /* same as pw[ 0 ] */
            
            /* set radix */
            r = (x + y) & 1;
            
            /* get drawverts */
            dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
            dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
            dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
            dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
            
            /* planar? */
            planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz );
            if( planar )
            {
                dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ];
                if( fabs( dist ) > PLANAR_EPSILON )
                    planar = qfalse;
            }
            
            /* generate a quad */
            if( planar )
            {
                rw.numVerts = 4;
                for( v = 0; v < 4; v++ )
                {
                    /* get most everything */
                    memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
                    
                    /* fix colors */
                    for( i = 0; i < MAX_LIGHTMAPS; i++ )
                    {
                        radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
                        VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
                        rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
                    }
                }
                
                /* subdivide into area lights */
                RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
            }
            
            /* generate 2 tris */
            else
            {
                rw.numVerts = 3;
                for( t = 0; t < 2; t++ )
                {
                    for( v = 0; v < 3 + t; v++ )
                    {
                        /* get "other" triangle (stupid hacky logic, but whatevah) */
                        if( v == 1 && t == 1 )
                            v++;

                        /* get most everything */
                        memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
                        
                        /* fix colors */
                        for( i = 0; i < MAX_LIGHTMAPS; i++ )
                        {
                            radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
                            VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
                            rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
                        }
                    }
                    
                    /* subdivide into area lights */
                    RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
                }
            }
        }
    }
    
    /* free the mesh */
    FreeMesh( mesh );
}
Ejemplo n.º 19
0
/**
 * @brief Parses a brush from the map file
 * @sa FindMiptex
 * @param[in] mapent The entity the brush to parse belongs to
 * @param[in] filename The map filename, used to derive the name for the footsteps file
 */
static void ParseBrush (entity_t* mapent, const char* filename)
{
	int j, k;
	brush_texture_t td;
	vec3_t planepts[3];
	const int checkOrFix = config.performMapCheck || config.fixMap ;

	if (nummapbrushes == MAX_MAP_BRUSHES)
		Sys_Error("nummapbrushes == MAX_MAP_BRUSHES (%i)", nummapbrushes);

	mapbrush_t* b = &mapbrushes[nummapbrushes];
	OBJZERO(*b);
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = num_entities - 1;
	b->brushnum = nummapbrushes - mapent->firstbrush;

	do {
		if (Q_strnull(GetToken()))
			break;
		if (*parsedToken == '}')
			break;

		if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
			Sys_Error("nummapbrushsides == MAX_MAP_BRUSHSIDES (%i)", nummapbrushsides);
		side_t* side = &brushsides[nummapbrushsides];

		/* read the three point plane definition */
		for (int i = 0; i < 3; i++) {
			if (i != 0)
				GetToken();
			if (*parsedToken != '(')
				Sys_Error("parsing brush");

			for (j = 0; j < 3; j++) {
				GetToken();
				planepts[i][j] = atof(parsedToken);
			}

			GetToken();
			if (*parsedToken != ')')
				Sys_Error("parsing brush");
		}

		/* read the texturedef */
		GetToken();
		if (strlen(parsedToken) >= MAX_TEXPATH) {
			if (config.performMapCheck || config.fixMap)
				Com_Printf("  ");/* hack to make this look like output from Check_Printf() */
			Com_Printf("ParseBrush: texture name too long (limit %i): %s\n", MAX_TEXPATH, parsedToken);
			if (config.fixMap)
				Sys_Error("Aborting, as -fix is active and saving might corrupt *.map by truncating texture name");
		}
		Q_strncpyz(td.name, parsedToken, sizeof(td.name));

		td.shift[0] = atof(GetToken());
		td.shift[1] = atof(GetToken());
		td.rotate = atof(GetToken());
		td.scale[0] = atof(GetToken());
		td.scale[1] = atof(GetToken());

		/* find default flags and values */
		const int mt = FindMiptex(td.name);
		side->surfaceFlags = td.surfaceFlags = side->contentFlags = td.value = 0;

		if (TokenAvailable()) {
			side->contentFlags = atoi(GetToken());
			side->surfaceFlags = td.surfaceFlags = atoi(GetToken());
			td.value = atoi(GetToken());
		}

		/* if in check or fix mode, let them choose to do this (with command line options),
		 * and then call is made elsewhere */
		if (!checkOrFix) {
			SetImpliedFlags(side, &td, b);
			/* if no other content flags are set - make this solid */
			if (!checkOrFix && side->contentFlags == 0)
				side->contentFlags = CONTENTS_SOLID;
		}

		/* translucent objects are automatically classified as detail and window */
		if (side->surfaceFlags & (SURF_BLEND33 | SURF_BLEND66 | SURF_ALPHATEST)) {
			side->contentFlags |= CONTENTS_DETAIL;
			side->contentFlags |= CONTENTS_TRANSLUCENT;
			side->contentFlags |= CONTENTS_WINDOW;
			side->contentFlags &= ~CONTENTS_SOLID;
		}
		if (config.fulldetail)
			side->contentFlags &= ~CONTENTS_DETAIL;
		if (!checkOrFix) {
			if (!(side->contentFlags & ((LAST_VISIBLE_CONTENTS - 1)
				| CONTENTS_ACTORCLIP | CONTENTS_WEAPONCLIP | CONTENTS_LIGHTCLIP)))
				side->contentFlags |= CONTENTS_SOLID;

			/* hints and skips are never detail, and have no content */
			if (side->surfaceFlags & (SURF_HINT | SURF_SKIP)) {
				side->contentFlags = 0;
				side->surfaceFlags &= ~CONTENTS_DETAIL;
			}
		}

		/* check whether the flags are ok */
		CheckFlags(side, b);

		/* generate a list of textures that should have footsteps when walking on them */
		if (mt > 0 && (side->surfaceFlags & SURF_FOOTSTEP))
			GenerateFootstepList(filename, mt);
		GenerateMaterialFile(filename, mt, side);

		/* find the plane number */
		int planenum = PlaneFromPoints(b, planepts[0], planepts[1], planepts[2]);
		if (planenum == PLANENUM_LEAF) {
			Com_Printf("Entity %i, Brush %i: plane with no normal\n", b->entitynum, b->brushnum);
			continue;
		}

		for (j = 0; j < 3; j++)
			VectorCopy(planepts[j], mapplanes[planenum].planeVector[j]);

		/* see if the plane has been used already */
		for (k = 0; k < b->numsides; k++) {
			const side_t* s2 = b->original_sides + k;
			if (s2->planenum == planenum) {
				Com_Printf("Entity %i, Brush %i: duplicate plane\n", b->entitynum, b->brushnum);
				break;
			}
			if (s2->planenum == (planenum ^ 1)) {
				Com_Printf("Entity %i, Brush %i: mirrored plane\n", b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
			continue;		/* duplicated */

		/* keep this side */
		side = b->original_sides + b->numsides;
		side->planenum = planenum;
		side->texinfo = TexinfoForBrushTexture(&mapplanes[planenum],
			&td, vec3_origin, side->contentFlags & CONTENTS_TERRAIN);
		side->brush = b;

		/* save the td off in case there is an origin brush and we
		 * have to recalculate the texinfo */
		side_brushtextures[nummapbrushsides] = td;

		Verb_Printf(VERB_DUMP, "Brush %i Side %i (%f %f %f) (%f %f %f) (%f %f %f) texinfo:%i[%s] plane:%i\n", nummapbrushes, nummapbrushsides,
			planepts[0][0], planepts[0][1], planepts[0][2],
			planepts[1][0], planepts[1][1], planepts[1][2],
			planepts[2][0], planepts[2][1], planepts[2][2],
			side->texinfo, td.name, planenum);

		nummapbrushsides++;
		b->numsides++;
	} while (1);

	/* get the content for the entire brush */
	b->contentFlags = BrushContents(b);

	/* copy all set face contentflags to the brush contentflags */
	for (int m = 0; m < b->numsides; m++)
		b->contentFlags |= b->original_sides[m].contentFlags;

	/* set DETAIL, TRANSLUCENT contentflags on all faces, if they have been set on any.
	 * called separately, if in check/fix mode */
	if (!checkOrFix)
		CheckPropagateParserContentFlags(b);

	/* allow detail brushes to be removed */
	if (config.nodetail && (b->contentFlags & CONTENTS_DETAIL)) {
		b->numsides = 0;
		return;
	}

	/* allow water brushes to be removed */
	if (config.nowater && (b->contentFlags & CONTENTS_WATER)) {
		b->numsides = 0;
		return;
	}

	/* create windings for sides and bounds for brush */
	MakeBrushWindings(b);

	Verb_Printf(VERB_DUMP, "Brush %i mins (%f %f %f) maxs (%f %f %f)\n", nummapbrushes,
		b->mbBox.mins[0], b->mbBox.mins[1], b->mbBox.mins[2],
		b->mbBox.maxs[0], b->mbBox.maxs[1], b->mbBox.maxs[2]);

	/* origin brushes are removed, but they set
	 * the rotation origin for the rest of the brushes (like func_door)
	 * in the entity. After the entire entity is parsed, the planenums
	 * and texinfos will be adjusted for the origin brush */
	if (!checkOrFix && (b->contentFlags & CONTENTS_ORIGIN)) {
		char string[32];
		vec3_t origin;

		if (num_entities == 1) {
			Sys_Error("Entity %i, Brush %i: origin brushes not allowed in world"
				, b->entitynum, b->brushnum);
			return;
		}

		b->mbBox.getCenter(origin);

		Com_sprintf(string, sizeof(string), "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue(&entities[b->entitynum], "origin", string);
		Verb_Printf(VERB_EXTRA, "Entity %i, Brush %i: set origin to %s\n", b->entitynum, b->brushnum, string);

		VectorCopy(origin, entities[b->entitynum].origin);

		/* don't keep this brush */
		b->numsides = 0;

		return;
	}

	if (!checkOrFix)
		AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
}
Ejemplo n.º 20
0
/*
=================
ParseBrush
=================
*/
void ParseBrush (entity_t *mapent)
{
	mapbrush_t		*b;
	int			i,j, k;
	int			mt;
	side_t		*side, *s2;
	int			planenum;
	brush_texture_t	td;
	int			planepts[3][3];

	if (nummapbrushes == MAX_MAP_BRUSHES)
		Error ("nummapbrushes == MAX_MAP_BRUSHES");

	b = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = num_entities-1;
	b->brushnum = nummapbrushes - mapent->firstbrush;

	do
	{
		if (!GetToken (true))
			break;
		if (!strcmp (token, "}") )
			break;

		if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
			Error ("MAX_MAP_BRUSHSIDES");
		side = &brushsides[nummapbrushsides];

		// read the three point plane definition
		for (i=0 ; i<3 ; i++)
		{
			if (i != 0)
				GetToken (true);
			if (strcmp (token, "(") )
				Error ("parsing brush");
			
			for (j=0 ; j<3 ; j++)
			{
				GetToken (false);
				planepts[i][j] = atoi(token);
			}
			
			GetToken (false);
			if (strcmp (token, ")") )
				Error ("parsing brush");
				
		}


		//
		// read the texturedef
		//
		GetToken (false);
		strcpy (td.name, token);

		GetToken (false);
		td.shift[0] = atoi(token);
		GetToken (false);
		td.shift[1] = atoi(token);
		GetToken (false);
		td.rotate = atoi(token);	
		GetToken (false);
		td.scale[0] = atof(token);
		GetToken (false);
		td.scale[1] = atof(token);

		// find default flags and values
		mt = FindMiptex (td.name);
		td.flags = textureref[mt].flags;
		td.value = textureref[mt].value;
		side->contents = textureref[mt].contents;
		side->surf = td.flags = textureref[mt].flags;

		if (TokenAvailable())
		{
			GetToken (false);
			side->contents = atoi(token);
			GetToken (false);
			side->surf = td.flags = atoi(token);
			GetToken (false);
			td.value = atoi(token);
		}

		// translucent objects are automatically classified as detail
		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
			side->contents |= CONTENTS_DETAIL;
		if (fulldetail)
			side->contents &= ~CONTENTS_DETAIL;
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 
			| CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST)  ) )
			side->contents |= CONTENTS_SOLID;

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT|SURF_SKIP) )
		{
			side->contents = 0;
			side->surf &= ~CONTENTS_DETAIL;
		}


		//
		// find the plane number
		//
		planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
		if (planenum == -1)
		{
			printf ("Entity %i, Brush %i: plane with no normal\n"
				, b->entitynum, b->brushnum);
			continue;
		}

		//
		// see if the plane has been used already
		//
		for (k=0 ; k<b->numsides ; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				printf ("Entity %i, Brush %i: duplicate plane\n"
					, b->entitynum, b->brushnum);
				break;
			}
			if ( s2->planenum == (planenum^1) )
			{
				printf ("Entity %i, Brush %i: mirrored plane\n"
					, b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
			continue;		// duplicated

		//
		// keep this side
		//

		side = b->original_sides + b->numsides;
		side->planenum = planenum;
		side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
			&td, vec3_origin);

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} while (1);

	// get the content for the entire brush
	b->contents = BrushContents (b);

	// allow detail brushes to be removed 
	if (nodetail && (b->contents & CONTENTS_DETAIL) )
	{
		b->numsides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
	{
		b->numsides = 0;
		return;
	}

	// create windings for sides and bounds for brush
	MakeBrushWindings (b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
	{
		c_clipbrushes++;
		for (i=0 ; i<b->numsides ; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	if (b->contents & CONTENTS_ORIGIN)
	{
		char	string[32];
		vec3_t	origin;

		if (num_entities == 1)
		{
			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
				, b->entitynum, b->brushnum);
			return;
		}

		VectorAdd (b->mins, b->maxs, origin);
		VectorScale (origin, 0.5, origin);

		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue (&entities[b->entitynum], "origin", string);

		VectorCopy (origin, entities[b->entitynum].origin);

		// don't keep this brush
		b->numsides = 0;

		return;
	}

	AddBrushBevels (b);

	nummapbrushes++;
	mapent->numbrushes++;		
}
Ejemplo n.º 21
0
/*
=================
ParseBrush
=================
*/
void ParseBrush (entity_t *mapent)
{
	char *tl;
	mapbrush_t		*b;
	int			i,j, k;
	int			mt;
	side_t		*side, *s2;
	int			planenum;
	brush_texture_t	td;
	float			planepts[3][3];
	qboolean		phongShading;

	MarkBrushBegin();

	if (nummapbrushes == MAX_MAP_BRUSHES)
		Error ("nummapbrushes == MAX_MAP_BRUSHES");

	b = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = num_entities-1;
	b->brushnum = nummapbrushes - mapent->firstbrush;

	// Knightmare added
	b->optimizedDetail = false;
	b->isTerrain = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname"))
				&& strlen(ValueForKey (&entities[b->entitynum], "terrain")) > 0);
	b->isGenSurf = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname"))
				&& strlen(ValueForKey (&entities[b->entitynum], "gensurf")) > 0);
	phongShading = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname"))
				&& strlen(ValueForKey (&entities[b->entitynum], "phongshading")) > 0);
	//if (b->isTerrain) 
	//	printf ("Brush number %i in enitity number %i has terrain flag set.\n", b->brushnum, b->entitynum);
	//if (b->phongShading) 
	//	printf ("Brush number %i in enitity number %i has phong shading flag set.\n", b->brushnum, b->entitynum);
	if (verbosebrushes)
		printf ("enitity %i, brush  %i\n", b->entitynum, b->brushnum);
	// end Knightmare

	do
	{
		if (!GetToken (true))
			break;
		if (!strcmp (token, "}") )
			break;

		if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
			Error ("MAX_MAP_BRUSHSIDES");
		side = &brushsides[nummapbrushsides];

		// read the three point plane definition
		for (i=0 ; i<3 ; i++)
		{
			if (i != 0)
				GetToken (true);
			if (strcmp (token, "(") )
				Error ("parsing brush\n  Brush: %s", i+1, brush_info);
			
			for (j=0 ; j<3 ; j++)
			{
				GetToken (false);
				planepts[i][j] = atof(token);
			}
			
			GetToken (false);
			if (strcmp (token, ")") )
				Error ("parsing brush\n  Brush: %s", i+1, brush_info);
				
		}

		//
		// read the texturedef
		//
		GetToken (false);
        strcpy (td.name, token);

		tl = td.name;

		for(tl = td.name; *tl != 0; tl++)
			*tl = tolower(*tl);

		GetToken (false);
		td.shift[0] = atoi(token);
		GetToken (false);
		td.shift[1] = atoi(token);
		GetToken (false);
		td.rotate = atoi(token);	
		GetToken (false);
		td.scale[0] = atof(token);
		GetToken (false);
		td.scale[1] = atof(token);

		// find default flags and values
		mt = FindMiptex (td.name);
		td.flags = textureref[mt].flags;
		td.value = textureref[mt].value;
		side->contents = textureref[mt].contents;
		side->surf = td.flags = textureref[mt].flags;

		if (TokenAvailable())
		{
			GetToken (false);
			side->contents = atoi(token);
			GetToken (false);
			side->surf = td.flags = atoi(token);
			GetToken (false);
			td.value = atoi(token);
		}

		// translucent objects are automatically classified as detail
		if (side->surf & (SURF_TRANS33|SURF_TRANS66|SURF_ALPHATEST) ) // Knightmare- added alphatest
			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
			side->contents |= CONTENTS_DETAIL;
		if (fulldetail)
			side->contents &= ~CONTENTS_DETAIL;
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 
			| CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST)  ) )
			side->contents |= CONTENTS_SOLID;

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT|SURF_SKIP) )
		{
			//side->contents = 0;
			//side->surf &= ~CONTENTS_DETAIL;
			side->contents &= CONTENTS_DETAIL; // allow only detail content- Geoffery DeWan?
		}

		//
		// find the plane number
		//
		planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
		if (planenum == -1)
		{
			printf ("Entity %i, Brush %i: plane with no normal\n  Brush: %s\n"
				, b->entitynum, b->brushnum, brush_info);
			continue;
		}

		//
		// see if the plane has been used already
		//
		for (k=0 ; k<b->numsides ; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				printf ("Entity %i, Brush %i: duplicate plane\n  Brush: %s\n"
					, b->entitynum, b->brushnum, brush_info);
				break;
			}
			if ( s2->planenum == (planenum^1) )
			{
				printf ("Entity %i, Brush %i: mirrored plane\n  Brush: %s\n"
					, b->entitynum, b->brushnum, brush_info);
				break;
			}
		}
		if (k != b->numsides)
			continue;		// duplicated

		//
		// keep this side
		//

		side = b->original_sides + b->numsides;
		side->planenum = planenum;
		side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
			&td, vec3_origin, b->isTerrain); // Knightmare added

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} while (1);

	// get the content for the entire brush
	b->contents = BrushContents (b);

	// allow detail brushes to be removed 
	if (nodetail && (b->contents & CONTENTS_DETAIL) )
	{
		b->numsides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
	{
		b->numsides = 0;
		return;
	}

	// Knightmare- check if this is an optimized detail brush (has caulk faces)
	// also exclude trans brushes and terrain
	if ((b->contents & CONTENTS_DETAIL) && (b->contents & CONTENTS_SOLID) && !b->isTerrain && !b->isGenSurf)
		for (i=0; i<b->numsides; i++)
		{
			if ( !strcmp(texinfo[b->original_sides[i].texinfo].texture, "system/caulk")
				|| !strcmp(texinfo[b->original_sides[i].texinfo].texture, "common/caulk") )
			{
				b->optimizedDetail = true;
				//printf ("Entity %i, Brush %i: optimized detail\n", b->entitynum, b->brushnum);
				break;
			}
		}

	// Knightmare- special handling for terrain brushes
	if (b->isTerrain || b->isGenSurf || phongShading)
		for (i=0; i<b->numsides; i++)
		{
			s2 = &b->original_sides[i];
			// set ArghRad phong shading value (because EasyGen/GTKGenSurf doesn't allow this)
			if (strcmp(texinfo[b->original_sides[i].texinfo].texture, "system/caulk")
				&& strcmp(texinfo[b->original_sides[i].texinfo].texture, "common/caulk"))
			{
				texinfo[s2->texinfo].value = 777 + b->entitynum;	// lucky 7's
				texinfo[s2->texinfo].flags &= ~SURF_LIGHT;			// must not be light-emitting
			}
		}

	// create windings for sides and bounds for brush

	// MEM_LEAK
	MakeBrushWindings (b);
	t_w = b->original_sides[0].winding;

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
	{
		c_clipbrushes++;
		for (i=0 ; i<b->numsides ; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	if (b->contents & CONTENTS_ORIGIN)
	{
		char	string[32];
		vec3_t	origin;

		if (num_entities == 1)
		{
			Error ("Entity %i, Brush %i: origin brushes not allowed in world\n  BrushL %s",
				b->entitynum, b->brushnum, brush_info);
			return;
		}

		VectorAdd (b->mins, b->maxs, origin);
		VectorScale (origin, 0.5, origin);

		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue (&entities[b->entitynum], "origin", string);

		VectorCopy (origin, entities[b->entitynum].origin);

		// don't keep this brush
		b->numsides = 0;

		return;
	}

	AddBrushBevels (b);

	nummapbrushes++;
	mapent->numbrushes++;		
}
Ejemplo n.º 22
0
/**
 * @brief Creates a new decal projector from a triangle.
 *
 * Projected polygons should be 3 or 4 points.
 *
 * If a single point is passed in (numPoints == 1) then the decal will be omnidirectional
 * omnidirectional decals use points[ 0 ] as center and projection[ 3 ] as radius
 * pass in lifeTime < 0 for a temporary mark.
 *
 * @param[in] hShader
 * @param[in] numPoints
 * @param[in] points
 * @param[in] projection
 * @param[in] color
 * @param[in] lifeTime
 * @param[in] fadeTime
 */
void RE_ProjectDecal(qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime,
                     int fadeTime)
{
	static int       totalProjectors = 0;
	vec3_t           xyz;
	decalVert_t      dv[4];
	int              i;
	decalProjector_t *dp, temp;

	if (r_numDecalProjectors >= MAX_DECAL_PROJECTORS)
	{
		Ren_Print("WARNING: RE_ProjectDecal() Max decal projectors reached (%d)\n", MAX_DECAL_PROJECTORS);
		return;
	}

	// dummy check
	if (numPoints != 1 && numPoints != 3 && numPoints != 4)
	{
		Ren_Print("WARNING: RE_ProjectDecal() Invalid number of decal points (%d)\n", numPoints);
		return;
	}

	// early outs
	if (lifeTime == 0)
	{
		Ren_Developer("WARNING: RE_ProjectDecal() lifeTime == 0\n"); // modders should have a look at this - vanilla does these calls
		return;
	}
	if (projection[3] <= 0.0f)
	{
		Ren_Print("WARNING: RE_ProjectDecal() projection[3] <= 0.0f\n");
		return;
	}

	// set times properly
	if (lifeTime < 0 || fadeTime < 0)
	{
		lifeTime = 0;
		fadeTime = 0;
	}

	// basic setup
	temp.shader        = R_GetShaderByHandle(hShader);
	temp.color[0]      = (byte)(color[0] * 255);
	temp.color[1]      = (byte)(color[1] * 255);
	temp.color[2]      = (byte)(color[2] * 255);
	temp.color[3]      = (byte)(color[3] * 255);
	temp.numPlanes     = numPoints + 2;
	temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; // FIXME: stale refdef time
	temp.fadeEndTime   = temp.fadeStartTime + fadeTime;
	temp.projectorNum  = 0;

	// set up decal texcoords (FIXME: support arbitrary projector st coordinates in trapcall)
	dv[0].st[0] = 0.0f;
	dv[0].st[1] = 0.0f;
	dv[1].st[0] = 0.0f;
	dv[1].st[1] = 1.0f;
	dv[2].st[0] = 1.0f;
	dv[2].st[1] = 1.0f;
	dv[3].st[0] = 1.0f;
	dv[3].st[1] = 0.0f;

	// omnidirectional?
	if (numPoints == 1)
	{
		float radius;
		float iDist;

		// set up omnidirectional
		numPoints            = 4;
		temp.numPlanes       = 6;
		temp.omnidirectional = qtrue;
		radius               = projection[3];

		Vector4Set(projection, 0.0f, 0.0f, -1.0f, radius * 2.0f);
		iDist = 1.0f / (radius * 2.0f);

		// set corner
		VectorSet(xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius);

		// make x axis texture matrix (yz)
		VectorSet(temp.texMat[0][0], 0.0f, iDist, 0.0f);
		temp.texMat[0][0][3] = -DotProduct(temp.texMat[0][0], xyz);
		VectorSet(temp.texMat[0][1], 0.0f, 0.0f, iDist);
		temp.texMat[0][1][3] = -DotProduct(temp.texMat[0][1], xyz);

		// make y axis texture matrix (xz)
		VectorSet(temp.texMat[1][0], iDist, 0.0f, 0.0f);
		temp.texMat[1][0][3] = -DotProduct(temp.texMat[1][0], xyz);
		VectorSet(temp.texMat[1][1], 0.0f, 0.0f, iDist);
		temp.texMat[1][1][3] = -DotProduct(temp.texMat[1][1], xyz);

		// make z axis texture matrix (xy)
		VectorSet(temp.texMat[2][0], iDist, 0.0f, 0.0f);
		temp.texMat[2][0][3] = -DotProduct(temp.texMat[2][0], xyz);
		VectorSet(temp.texMat[2][1], 0.0f, iDist, 0.0f);
		temp.texMat[2][1][3] = -DotProduct(temp.texMat[2][1], xyz);

		// setup decal points
		VectorSet(dv[0].xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius);
		VectorSet(dv[1].xyz, points[0][0] - radius, points[0][1] + radius, points[0][2] + radius);
		VectorSet(dv[2].xyz, points[0][0] + radius, points[0][1] + radius, points[0][2] + radius);
		VectorSet(dv[3].xyz, points[0][0] + radius, points[0][1] - radius, points[0][2] + radius);
	}
	else
	{
		// set up unidirectional
		temp.omnidirectional = qfalse;

		// set up decal points
		VectorCopy(points[0], dv[0].xyz);
		VectorCopy(points[1], dv[1].xyz);
		VectorCopy(points[2], dv[2].xyz);
		VectorCopy(points[3], dv[3].xyz);

		// make texture matrix
		if (!MakeTextureMatrix(temp.texMat[0], projection, &dv[0], &dv[1], &dv[2]))
		{
			Ren_Print("WARNING: RE_ProjectDecal() MakeTextureMatrix returns NULL\n");
			return;
		}
	}

	// bound the projector
	ClearBounds(temp.mins, temp.maxs);
	for (i = 0; i < numPoints; i++)
	{
		AddPointToBounds(dv[i].xyz, temp.mins, temp.maxs);
		VectorMA(dv[i].xyz, projection[3], projection, xyz);
		AddPointToBounds(xyz, temp.mins, temp.maxs);
	}

	// make bounding sphere
	VectorAdd(temp.mins, temp.maxs, temp.center);
	VectorScale(temp.center, 0.5f, temp.center);
	VectorSubtract(temp.maxs, temp.center, xyz);
	temp.radius  = VectorLength(xyz);
	temp.radius2 = temp.radius * temp.radius;

	// make the front plane
	if (!PlaneFromPoints(temp.planes[0], dv[0].xyz, dv[1].xyz, dv[2].xyz))
	{
		Ren_Developer("WARNING: RE_ProjectDecal() PlaneFromPoints is NULL\n"); // occurs on UJE_fueldump
		return;
	}

	// make the back plane
	VectorSubtract(vec3_origin, temp.planes[0], temp.planes[1]);
	VectorMA(dv[0].xyz, projection[3], projection, xyz);
	temp.planes[1][3] = DotProduct(xyz, temp.planes[1]);

	// make the side planes
	for (i = 0; i < numPoints; i++)
	{
		VectorMA(dv[i].xyz, projection[3], projection, xyz);
		if (!PlaneFromPoints(temp.planes[i + 2], dv[(i + 1) % numPoints].xyz, dv[i].xyz, xyz))
		{
			Ren_Developer("WARNING: RE_ProjectDecal() a side plane is NULL\n"); // occurs on map venice
			return;
		}
	}

	// create a new projector
	dp = &backEndData->decalProjectors[r_numDecalProjectors];
	Com_Memcpy(dp, &temp, sizeof(*dp));
	dp->projectorNum = totalProjectors++;

	// we have a winner
	r_numDecalProjectors++;
}
Ejemplo n.º 23
0
/*
=================
Q2_ParseBrush
=================
*/
void Q2_ParseBrush(script_t *script, entity_t *mapent)
{
	mapbrush_t      *b;
	int             i, j, k;
	int             mt;
	side_t          *side, *s2;
	int             planenum;
	brush_texture_t td;
	int             planepts[3][3];
	token_t         token;

	if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
	{
		Error("nummapbrushes == MAX_MAPFILE_BRUSHES");
	}

	b                 = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum      = num_entities - 1;
	b->brushnum       = nummapbrushes - mapent->firstbrush;
	b->leafnum        = -1;

	do
	{
		if (!PS_ReadToken(script, &token))
		{
			break;
		}
		if (!strcmp(token.string, "}"))
		{
			break;
		}

		//IDBUG: mixed use of MAX_MAPFILE_? and MAX_MAP_? this could
		//			lead to out of bound indexing of the arrays
		if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
		{
			Error("MAX_MAPFILE_BRUSHSIDES");
		}
		side = &brushsides[nummapbrushsides];

		//read the three point plane definition
		for (i = 0; i < 3; i++)
		{
			if (i != 0)
			{
				PS_ExpectTokenString(script, "(");
			}
			for (j = 0; j < 3; j++)
			{
				PS_ExpectAnyToken(script, &token);
				planepts[i][j] = atof(token.string);
			} //end for
			PS_ExpectTokenString(script, ")");
		} //end for

		//
		//read the texturedef
		//
		PS_ExpectAnyToken(script, &token);
		strcpy(td.name, token.string);

		PS_ExpectAnyToken(script, &token);
		td.shift[0] = atol(token.string);
		PS_ExpectAnyToken(script, &token);
		td.shift[1] = atol(token.string);
		PS_ExpectAnyToken(script, &token);
		td.rotate = atol(token.string);
		PS_ExpectAnyToken(script, &token);
		td.scale[0] = atof(token.string);
		PS_ExpectAnyToken(script, &token);
		td.scale[1] = atof(token.string);

		//find default flags and values
		mt             = FindMiptex(td.name);
		td.flags       = textureref[mt].flags;
		td.value       = textureref[mt].value;
		side->contents = textureref[mt].contents;
		side->surf     = td.flags = textureref[mt].flags;

		//check if there's a number available
		if (PS_CheckTokenType(script, TT_NUMBER, 0, &token))
		{
			side->contents = token.intvalue;
			PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
			side->surf = td.flags = token.intvalue;
			PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
			td.value = token.intvalue;
		}

		// translucent objects are automatically classified as detail
//		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
//			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
		{
			side->contents |= CONTENTS_DETAIL;
		}
		if (fulldetail)
		{
			side->contents &= ~CONTENTS_DETAIL;
		}
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS - 1)
		                        | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP | CONTENTS_MIST)))
		{
			side->contents |= CONTENTS_SOLID;
		}

		// hints and skips are never detail, and have no content
//		if (side->surf & (SURF_HINT|SURF_SKIP) )
//		{
//			side->contents = 0;
//			side->surf &= ~CONTENTS_DETAIL;
//		}

#ifdef ME
		//for creating AAS... this side is textured
		side->flags |= SFL_TEXTURED;
#endif //ME
		//
		// find the plane number
		//
		planenum = PlaneFromPoints(planepts[0], planepts[1], planepts[2]);
		if (planenum == -1)
		{
			Log_Print("Entity %i, Brush %i: plane with no normal\n"
			          , b->entitynum, b->brushnum);
			continue;
		}

		//
		// see if the plane has been used already
		//
		for (k = 0 ; k < b->numsides ; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				Log_Print("Entity %i, Brush %i: duplicate plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
			if (s2->planenum == (planenum ^ 1))
			{
				Log_Print("Entity %i, Brush %i: mirrored plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
		{
			continue;       // duplicated

		}
		//
		// keep this side
		//

		side           = b->original_sides + b->numsides;
		side->planenum = planenum;
		side->texinfo  = TexinfoForBrushTexture(&mapplanes[planenum],
		                                        &td, vec3_origin);

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	}
	while (1);

	// get the content for the entire brush
	b->contents = Q2_BrushContents(b);

#ifdef ME
	if (BrushExists(b))
	{
		c_squattbrushes++;
		b->numsides = 0;
		return;
	} //end if

	if (create_aas)
	{
		//create AAS brushes, and add brush bevels
		AAS_CreateMapBrushes(b, mapent, true);
		//NOTE: if we return here then duplicate plane errors occur for the non world entities
		return;
	} //end if
#endif //ME

	// allow detail brushes to be removed
	if (nodetail && (b->contents & CONTENTS_DETAIL))
	{
		b->numsides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)))
	{
		b->numsides = 0;
		return;
	}

	// create windings for sides and bounds for brush
	MakeBrushWindings(b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
	{
		c_clipbrushes++;
		for (i = 0 ; i < b->numsides ; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	if (b->contents & CONTENTS_ORIGIN)
	{
		char   string[32];
		vec3_t origin;

		if (num_entities == 1)
		{
			Error("Entity %i, Brush %i: origin brushes not allowed in world"
			      , b->entitynum, b->brushnum);
			return;
		}

		VectorAdd(b->mins, b->maxs, origin);
		VectorScale(origin, 0.5, origin);

		sprintf(string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue(&entities[b->entitynum], "origin", string);

		VectorCopy(origin, entities[b->entitynum].origin);

		// don't keep this brush
		b->numsides = 0;

		return;
	}

	AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
}
Ejemplo n.º 24
0
static void ProjectDecalOntoWinding( decalProjector_t *dp, int numPoints, vec3_t points[ 2 ][ MAX_DECAL_VERTS ], bspSurface_t *surf,
                                     bspModel_t *bmodel )
{
	int        i, pingPong, count, axis;
	float      pd, d, d2, alpha = 1.f;
	vec4_t     plane;
	vec3_t     absNormal;
	decal_t    *decal, *oldest;
	polyVert_t *vert;

	/* make a plane from the winding */
	if ( !PlaneFromPoints( plane, points[ 0 ][ 0 ], points[ 0 ][ 1 ], points[ 0 ][ 2 ] ) )
	{
		return;
	}

	/* omnidirectional projectors need plane type */
	if ( dp->omnidirectional )
	{
		/* compiler warnings be gone */
		pd = 1.0f;

		/* fade by distance from plane */
		d = DotProduct( dp->center, plane ) - plane[ 3 ];
		alpha = 1.0f - ( fabs( d ) / dp->radius );

		if ( alpha < 0.0f )
		{
			return;
		}

		if ( alpha > 1.0f )
		{
			alpha = 1.0f;
		}

		/* set projection axis */
		absNormal[ 0 ] = fabs( plane[ 0 ] );
		absNormal[ 1 ] = fabs( plane[ 1 ] );
		absNormal[ 2 ] = fabs( plane[ 2 ] );

		if ( absNormal[ 2 ] >= absNormal[ 0 ] && absNormal[ 2 ] >= absNormal[ 1 ] )
		{
			axis = 2;
		}
		else if ( absNormal[ 0 ] >= absNormal[ 1 ] && absNormal[ 0 ] >= absNormal[ 2 ] )
		{
			axis = 0;
		}
		else
		{
			axis = 1;
		}
	}
	else
	{
		/* backface check */
		pd = DotProduct( dp->planes[ 0 ], plane );

		if ( pd < -0.0001f )
		{
			return;
		}

		/* directional decals use first texture matrix */
		axis = 0;
	}

	/* chop the winding by all the projector planes */
	pingPong = 0;

	for ( i = 0; i < dp->numPlanes; i++ ) //%    dp->numPlanes
	{
		ChopWindingBehindPlane( numPoints, points[ pingPong ], &numPoints, points[ !pingPong ], dp->planes[ i ], 0.0f );
		pingPong ^= 1;

		if ( numPoints < 3 )
		{
			return;
		}

		if ( numPoints == MAX_DECAL_VERTS )
		{
			break;
		}
	}

	/* find first free decal (fixme: optimize this) */
	count = ( bmodel == tr.world->models ? MAX_WORLD_DECALS : MAX_ENTITY_DECALS );
	oldest = &bmodel->decals[ 0 ];
	decal = bmodel->decals;

	for ( i = 0; i < count; i++, decal++ )
	{
		/* try to find an empty decal slot */
		if ( decal->shader == NULL )
		{
			break;
		}

		/* find oldest decal */
		if ( decal->fadeEndTime < oldest->fadeEndTime )
		{
			oldest = decal;
		}
	}

	/* guess we have to use the oldest decal */
	if ( i >= count )
	{
		decal = oldest;
	}

	/* r_speeds useful info */
	tr.pc.c_decalSurfacesCreated++;

	/* set it up (fixme: get the shader before this happens) */
	decal->parent = surf;
	decal->shader = dp->shader;
	decal->fadeStartTime = dp->fadeStartTime;
	decal->fadeEndTime = dp->fadeEndTime;
	decal->fogIndex = surf->fogIndex;

	/* add points */
	decal->numVerts = numPoints;
	vert = decal->verts;

	for ( i = 0; i < numPoints; i++, vert++ )
	{
		/* set xyz */
		VectorCopy( points[ pingPong ][ i ], vert->xyz );

		/* set st */
		vert->st[ 0 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 0 ] ) + dp->texMat[ axis ][ 0 ][ 3 ];
		vert->st[ 1 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 1 ] ) + dp->texMat[ axis ][ 1 ][ 3 ];

		/* unidirectional decals fade by half distance from front->back planes */
		if ( !dp->omnidirectional )
		{
			/* set alpha */
			d = DotProduct( vert->xyz, dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ];
			d2 = DotProduct( vert->xyz, dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ];
			alpha = 2.0f * d2 / ( d + d2 );

			if ( alpha > 1.0f )
			{
				alpha = 1.0f;
			}
			else if ( alpha < 0.0f )
			{
				alpha = 0.0f;
			}
		}

		/* set color */
		vert->modulate[ 0 ] = Q_ftol( pd * alpha * dp->color[ 0 ] );
		vert->modulate[ 1 ] = Q_ftol( pd * alpha * dp->color[ 1 ] );
		vert->modulate[ 2 ] = Q_ftol( pd * alpha * dp->color[ 2 ] );
		vert->modulate[ 3 ] = Q_ftol( alpha * dp->color[ 3 ] );
	}
}
Ejemplo n.º 25
0
static int MakeDecalProjector( shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv )
{
	int					i, j;
	decalProjector_t	*dp;
	vec3_t				xyz;
	
	
	/* dummy check */
	if( numVerts != 3 && numVerts != 4 )
		return -1;
	
	/* limit check */
	if( numProjectors >= MAX_PROJECTORS )
	{
		MsgDev( D_WARN, "MAX_PROJECTORS (%d) exceeded, no more decal projectors available.\n", MAX_PROJECTORS );
		return -2;
	}
	
	/* create a new projector */
	dp = &projectors[ numProjectors ];
	Mem_Set( dp, 0, sizeof( *dp ));
	
	/* basic setup */
	dp->si = si;
	dp->numPlanes = numVerts + 2;
	
	/* make texture matrix */
	if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) )
		return -1;
	
	/* bound the projector */
	ClearBounds( dp->mins, dp->maxs );
	for( i = 0; i < numVerts; i++ )
	{
		AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs );
		VectorMA( dv[ i ]->xyz, distance, projection, xyz );
		AddPointToBounds( xyz, dp->mins, dp->maxs );
	}
	
	/* make bouding sphere */
	VectorAdd( dp->mins, dp->maxs, dp->center );
	VectorScale( dp->center, 0.5f, dp->center );
	VectorSubtract( dp->maxs, dp->center, xyz );
	dp->radius = VectorLength( xyz );
	dp->radius2 = dp->radius * dp->radius;
	
	/* make the front plane */
	if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) )
		return -1;
	
	/* make the back plane */
	VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] );
	VectorMA( dv[ 0 ]->xyz, distance, projection, xyz );
	dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] );
	
	/* make the side planes */
	for( i = 0; i < numVerts; i++ )
	{
		j = (i + 1) % numVerts;
		VectorMA( dv[ i ]->xyz, distance, projection, xyz );
		if( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) )
			return -1;
	}
	
	/* return ok */
	numProjectors++;
	return numProjectors - 1;
}
Ejemplo n.º 26
0
/*
* R_RenderMeshGLSL_Distortion
*/
static void R_RenderMeshGLSL_Distortion( r_glslfeat_t programFeatures )
{
	int i, last_slot;
	unsigned last_framenum;
	int state, tcgen;
	int width = 1, height = 1;
	int program, object;
	mat4x4_t unused;
	cplane_t plane;
	const char *key;
	shaderpass_t *pass = r_back.accumPasses[0];
	image_t *portaltexture[2];
	qboolean frontPlane;

	PlaneFromPoints( r_back.r_triangle0Copy, &plane );
	plane.dist += DotProduct( ri.currententity->origin, plane.normal );
	key = R_PortalKeyForPlane( &plane );
	last_framenum = last_slot = 0;

	for( i = 0; i < 2; i++ )
	{
		int slot;

		portaltexture[i] = NULL;

		slot = R_FindPortalTextureSlot( key, i+1 );
		if( slot )
			portaltexture[i] = r_portaltextures[slot-1];

		if( portaltexture[i] == NULL )
		{
			portaltexture[i] = r_blacktexture;
		}
		else
		{
			width = portaltexture[i]->upload_width;
			height = portaltexture[i]->upload_height;
		}

		// find the most recently updated texture
		if( portaltexture[i]->framenum > last_framenum )
		{
			last_slot = i;
			last_framenum = i;
		}
	}

	// if textures were not updated sequentially, use the most recent one
	// and reset the remaining to black
	if( portaltexture[0]->framenum+1 != portaltexture[1]->framenum )
		portaltexture[(last_slot+1)&1] = r_blacktexture;

	if( pass->anim_frames[0] != r_blankbumptexture )
		programFeatures |= GLSL_DISTORTION_APPLY_DUDV;
	if( ri.params & RP_CLIPPLANE )
		programFeatures |= GLSL_COMMON_APPLY_CLIPPING;
	if( pass->flags & SHADERPASS_GRAYSCALE )
		programFeatures |= GLSL_COMMON_APPLY_GRAYSCALE;
	if( portaltexture[0] != r_blacktexture )
		programFeatures |= GLSL_DISTORTION_APPLY_REFLECTION;
	if( portaltexture[1] != r_blacktexture )
		programFeatures |= GLSL_DISTORTION_APPLY_REFRACTION;

	frontPlane = (PlaneDiff( ri.viewOrigin, &ri.portalPlane ) > 0 ? qtrue : qfalse);

	if( frontPlane )
	{
		if( pass->alphagen.type != ALPHA_GEN_IDENTITY )
			programFeatures |= GLSL_DISTORTION_APPLY_DISTORTION_ALPHA;
	}

	tcgen = pass->tcgen;                // store the original tcgen

	R_BindShaderpass( pass, pass->anim_frames[0], 0, NULL );  // dudvmap

	// calculate the fragment color
	R_ModifyColor( pass, programFeatures & GLSL_DISTORTION_APPLY_DISTORTION_ALPHA ? qtrue : qfalse, qfalse );

	GL_TexEnv( GL_MODULATE );

	// set shaderpass state (blending, depthwrite, etc)
	state = r_back.currentShaderState | ( pass->flags & r_back.currentShaderPassMask ) | GLSTATE_BLEND_MTEX;
	GL_SetState( state );

	if( pass->anim_frames[1] )
	{	// eyeDot
		programFeatures |= GLSL_DISTORTION_APPLY_EYEDOT;

		pass->tcgen = TC_GEN_SVECTORS;
		GL_Bind( 1, pass->anim_frames[1] ); // normalmap
		GL_SetTexCoordArrayMode( GL_TEXTURE_COORD_ARRAY );
		R_VertexTCBase( pass, 1, unused, NULL );
	}

	GL_Bind( 2, portaltexture[0] );            // reflection
	GL_Bind( 3, portaltexture[1] );           // refraction

	pass->tcgen = tcgen;    // restore original tcgen

	// update uniforms
	program = R_RegisterGLSLProgram( pass->program_type, pass->program, NULL, NULL, NULL, 0, programFeatures );
	object = R_GetProgramObject( program );
	if( object )
	{
		qglUseProgramObjectARB( object );

		R_UpdateProgramUniforms( program, ri.viewOrigin, vec3_origin, vec3_origin, NULL, NULL, NULL,
			frontPlane, width, height, 0, 0, 0, 
			colorArrayCopy[0], r_back.overBrightBits, r_back.currentShaderTime, r_back.entityColor );

		R_FlushArrays();

		qglUseProgramObjectARB( 0 );
	}
}
Ejemplo n.º 27
0
static int MakeDecalProjector( int mapEntityNum, shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv, float backfacecull, float lightmapScale, vec3_t lightmapAxis, vec3_t minlight, vec3_t minvertexlight, vec3_t ambient, vec3_t colormod, int smoothNormals )
{
	int					i, j;
	decalProjector_t	*dp;
	vec3_t				xyz;

	/* dummy check */
	if( numVerts != 3 && numVerts != 4 )
		return -1;
	
	/* limit check */
	if( numProjectors >= MAX_PROJECTORS )
	{
		Sys_Warning( mapEntityNum, "MAX_PROJECTORS (%d) exceeded, no more decal projectors available.", MAX_PROJECTORS );
		return -2;
	}
	
	/* create a new projector */
	dp = &projectors[ numProjectors ];
	memset( dp, 0, sizeof( decalProjector_t ) );
	
	/* basic setup */
	dp->si = si;
	dp->numPlanes = numVerts + 2;
	dp->backfacecull = backfacecull;
	dp->lightmapScale = lightmapScale;
	VectorCopy( lightmapAxis, dp->lightmapAxis );
	VectorCopy( minlight, dp->minlight );
	VectorCopy( minvertexlight, dp->minvertexlight );
	VectorCopy( ambient, dp->ambient );
	VectorCopy( colormod, dp->colormod );
	dp->smoothNormals = smoothNormals;
	dp->mapEntityNum = mapEntityNum;
	
	/* make texture matrix */
	if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) )
		return -1;
	
	/* bound the projector */
	ClearBounds( dp->mins, dp->maxs );
	for( i = 0; i < numVerts; i++ )
	{
		AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs );
		VectorMA( dv[ i ]->xyz, distance, projection, xyz );
		AddPointToBounds( xyz, dp->mins, dp->maxs );
	}
	
	/* make bouding sphere */
	VectorAdd( dp->mins, dp->maxs, dp->center );
	VectorScale( dp->center, 0.5f, dp->center );
	VectorSubtract( dp->maxs, dp->center, xyz );
	dp->radius = VectorLength( xyz );
	dp->radius2 = dp->radius * dp->radius;
	
	/* make the front plane */
	if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) )
		return -1;
	
	/* make the back plane */
	VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] );
	VectorMA( dv[ 0 ]->xyz, distance, projection, xyz );
	dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] );
	
	/* make the side planes */
	for( i = 0; i < numVerts; i++ )
	{
		j = (i + 1) % numVerts;
		VectorMA( dv[ i ]->xyz, distance, projection, xyz );
		if( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) )
			return -1;
	}
	
	/* return ok */
	numProjectors++;
	return numProjectors - 1;
}