Esempio n. 1
0
File: fog.c Progetto: otty/cake3
/*
====================
SplitMeshByPlane
====================
*/
void SplitMeshByPlane(mesh_t * in, vec3_t normal, float dist, mesh_t ** front, mesh_t ** back)
{
	int             w, h, split;
	float           d[MAX_PATCH_SIZE][MAX_PATCH_SIZE];
	drawVert_t     *dv, *v1, *v2;
	int             c_front, c_back, c_on;
	mesh_t         *f, *b;
	int             i;
	float           frac;
	int             frontAprox, backAprox;

	for(i = 0; i < 2; i++)
	{
		dv = in->verts;
		c_front = 0;
		c_back = 0;
		c_on = 0;
		for(h = 0; h < in->height; h++)
		{
			for(w = 0; w < in->width; w++, dv++)
			{
				d[h][w] = DotProduct(dv->xyz, normal) - dist;
				if(d[h][w] > ON_EPSILON)
				{
					c_front++;
				}
				else if(d[h][w] < -ON_EPSILON)
				{
					c_back++;
				}
				else
				{
					c_on++;
				}
			}
		}

		*front = NULL;
		*back = NULL;

		if(!c_front)
		{
			*back = in;
			return;
		}
		if(!c_back)
		{
			*front = in;
			return;
		}

		// find a split point
		split = -1;
		for(w = 0; w < in->width - 1; w++)
		{
			if((d[0][w] < 0) != (d[0][w + 1] < 0))
			{
				if(split == -1)
				{
					split = w;
					break;
				}
			}
		}

		if(split == -1)
		{
			if(i == 1)
			{
				Sys_FPrintf(SYS_VRB, "No crossing points in patch\n");
				*front = in;
				return;
			}

			in = TransposeMesh(in);
			InvertMesh(in);
			continue;
		}

		// make sure the split point stays the same for all other rows
		for(h = 1; h < in->height; h++)
		{
			for(w = 0; w < in->width - 1; w++)
			{
				if((d[h][w] < 0) != (d[h][w + 1] < 0))
				{
					if(w != split)
					{
						Sys_Printf("multiple crossing points for patch -- can't clip\n");
						*front = in;
						return;
					}
				}
			}
			if((d[h][split] < 0) == (d[h][split + 1] < 0))
			{
				Sys_Printf("differing crossing points for patch -- can't clip\n");
				*front = in;
				return;
			}
		}

		break;
	}


	// create two new meshes
	f = malloc(sizeof(*f));
	f->width = split + 2;
	if(!(f->width & 1))
	{
		f->width++;
		frontAprox = 1;
	}
	else
	{
		frontAprox = 0;
	}
	if(f->width > MAX_PATCH_SIZE)
	{
		Error("MAX_PATCH_SIZE after split");
	}
	f->height = in->height;
	f->verts = malloc(sizeof(f->verts[0]) * f->width * f->height);

	b = malloc(sizeof(*b));
	b->width = in->width - split;
	if(!(b->width & 1))
	{
		b->width++;
		backAprox = 1;
	}
	else
	{
		backAprox = 0;
	}
	if(b->width > MAX_PATCH_SIZE)
	{
		Error("MAX_PATCH_SIZE after split");
	}
	b->height = in->height;
	b->verts = malloc(sizeof(b->verts[0]) * b->width * b->height);

	if(d[0][0] > 0)
	{
		*front = f;
		*back = b;
	}
	else
	{
		*front = b;
		*back = f;
	}

	// distribute the points
	for(w = 0; w < in->width; w++)
	{
		for(h = 0; h < in->height; h++)
		{
			if(w <= split)
			{
				f->verts[h * f->width + w] = in->verts[h * in->width + w];
			}
			else
			{
				b->verts[h * b->width + w - split + backAprox] = in->verts[h * in->width + w];
			}
		}
	}

	// clip the crossing line
	for(h = 0; h < in->height; h++)
	{
		dv = &f->verts[h * f->width + split + 1];
		v1 = &in->verts[h * in->width + split];
		v2 = &in->verts[h * in->width + split + 1];
		frac = d[h][split] / (d[h][split] - d[h][split + 1]);
		for(i = 0; i < 10; i++)
		{
			dv->xyz[i] = v1->xyz[i] + frac * (v2->xyz[i] - v1->xyz[i]);
		}
		dv->xyz[10] = 0;		//set all 4 colors to 0 
		if(frontAprox)
		{
			f->verts[h * f->width + split + 2] = *dv;
		}
		b->verts[h * b->width] = *dv;
		if(backAprox)
		{
			b->verts[h * b->width + 1] = *dv;
		}
	}

	/*
	   PrintMesh( in );
	   Sys_Printf("\n");
	   PrintMesh( f );
	   Sys_Printf("\n");
	   PrintMesh( b );
	   Sys_Printf("\n");
	 */

	FreeMesh(in);
}
Esempio n. 2
0
File: fog.c Progetto: Elzair/q3map2
qboolean ChopPatchSurfaceByBrush( entity_t *e, mapDrawSurface_t *ds, brush_t *b ){
	int i, j;
	side_t      *s;
	plane_t     *plane;
	mesh_t      *outside[MAX_BRUSH_SIDES];
	int numOutside;
	mesh_t      *m, *front, *back;
	mapDrawSurface_t    *newds;

	m = DrawSurfToMesh( ds );
	numOutside = 0;

	// only split by the top and bottom planes to avoid
	// some messy patch clipping issues

	for ( i = 4 ; i <= 5 ; i++ ) {
		s = &b->sides[ i ];
		plane = &mapplanes[ s->planenum ];

		SplitMeshByPlane( m, plane->normal, plane->dist, &front, &back );

		if ( !back ) {
			// nothing actually contained inside
			for ( j = 0 ; j < numOutside ; j++ ) {
				FreeMesh( outside[j] );
			}
			return qfalse;
		}
		m = back;

		if ( front ) {
			if ( numOutside == MAX_BRUSH_SIDES ) {
				Error( "MAX_BRUSH_SIDES" );
			}
			outside[ numOutside ] = front;
			numOutside++;
		}
	}

	/* all of outside fragments become seperate drawsurfs */
	numFogPatchFragments += numOutside;
	for ( i = 0; i < numOutside; i++ )
	{
		/* transpose and invert the chopped patch (fixes potential crash. fixme: why?) */
		outside[ i ] = TransposeMesh( outside[ i ] );
		InvertMesh( outside[ i ] );

		/* ydnar: do this the hacky right way */
		newds = AllocDrawSurface( SURFACE_PATCH );
		memcpy( newds, ds, sizeof( *ds ) );
		newds->patchWidth = outside[ i ]->width;
		newds->patchHeight = outside[ i ]->height;
		newds->numVerts = outside[ i ]->width * outside[ i ]->height;
		newds->verts = safe_malloc( newds->numVerts * sizeof( *newds->verts ) );
		memcpy( newds->verts, outside[ i ]->verts, newds->numVerts * sizeof( *newds->verts ) );

		/* free the source mesh */
		FreeMesh( outside[ i ] );
	}

	/* only rejigger this patch if it was chopped */
	//%	Sys_Printf( "Inside: %d x %d\n", m->width, m->height );
	if ( numOutside > 0 ) {
		/* transpose and invert the chopped patch (fixes potential crash. fixme: why?) */
		m = TransposeMesh( m );
		InvertMesh( m );

		/* replace ds with m */
		ds->patchWidth = m->width;
		ds->patchHeight = m->height;
		ds->numVerts = m->width * m->height;
		free( ds->verts );
		ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
		memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );
	}

	/* free the source mesh and return */
	FreeMesh( m );
	return qtrue;
}