Ejemplo n.º 1
0
/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */
void Map_ImportEntities( CPtrArray *ents, bool bAddSelected = false ){
	int num_ents, num_brushes;
	CPtrArray *brushes;
	vec3_t mins, maxs;
	entity_t *e;
	brush_t *b;
	face_t *f;
	int i,j;

	GPtrArray *new_ents = g_ptr_array_new();

	g_qeglobals.bPrimitBrushes = false;

	brush_t *pBrushList = ( bAddSelected ) ? &selected_brushes : &active_brushes;

	bool bDoneBPCheck = false;
	g_qeglobals.bNeedConvert = false;
	// HACK: find out if this map file was a BP one
	// check the first brush in the file that is NOT a patch
	// this will not be necessary when we allow both formats in the same file
	num_ents = ents->GetSize();
	for ( i = 0; !bDoneBPCheck && i < num_ents; i++ )
	{
		e = (entity_t*)ents->GetAt( i );
		brushes = (CPtrArray*)e->pData;
		num_brushes = brushes->GetSize();
		for ( j = 0; !bDoneBPCheck && j < num_brushes; j++ )
		{
			/*!todo Allow mixing texdef formats per-face. */
			b = (brush_t *)brushes->GetAt( j );
			if ( b->patchBrush ) {
				continue;
			}
			bDoneBPCheck = true;
			int BP_param = -1;
			if ( b->bBrushDef && !g_qeglobals.m_bBrushPrimitMode ) {
				BP_param = 0;
			}
			else if ( !b->bBrushDef && g_qeglobals.m_bBrushPrimitMode ) {
				BP_param = 1;
			}

			if ( BP_param != -1 ) {
				switch ( BP_MessageBox( BP_param ) )
				{
				case 0:
					Map_FreeEntities( ents );
					return;
				case 1:
					g_qeglobals.bNeedConvert = true;
					break;
				case 2:
					g_qeglobals.bNeedConvert = false;
					break;
				}
			}
		}
	}

	// process the entities into the world geometry
	num_ents = ents->GetSize();
	for ( i = 0; i < num_ents; i++ )
	{
		num_brushes = 0;
		e = (entity_t*)ents->GetAt( i );
		brushes = (CPtrArray*)e->pData;

		num_brushes = brushes->GetSize();
		// link brushes into entity
		for ( j = 0; j < num_brushes; j++ )
		{
			Entity_LinkBrush( e, (brush_t *)brushes->GetAt( j ) );
			g_qeglobals.d_parsed_brushes++;
		}
		brushes->RemoveAll();
		delete brushes;
		e->pData = NULL;

		// set entity origin
		GetVectorForKey( e, "origin", e->origin );
		// set entity eclass
		/*!\todo Make SetKeyValue check for "classname" change and assign appropriate eclass */
		e->eclass = Eclass_ForName( ValueForKey( e, "classname" ),
									( e->brushes.onext != &e->brushes ) );

		// go through all parsed brushes and build stuff
		for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
		{
			for ( f = b->brush_faces; f != NULL; f = f->next )
			{
				f->pShader = QERApp_Shader_ForName( f->texdef.GetName() );
				f->d_texture = f->pShader->getTexture();
			}

			// when brushes are in final state, build the planes and windings
			// NOTE: also converts BP brushes if g_qeglobals.bNeedConvert is true
			Brush_Build( b );
		}

//#define TERRAIN_HACK
#undef TERRAIN_HACK

#ifdef TERRAIN_HACK
		if ( ( strcmp( ValueForKey( e, "terrain" ),"1" ) == 0 && strcmp( e->eclass->name,"func_group" ) == 0 ) ) {

			// two aux pointers to the shaders used in the terrain entity
			// we don't keep refcount on them since they are only temporary
			// this avoids doing expensive lookups by name for all faces
			IShader *pTerrainShader, *pCaulk;

			pTerrainShader = NULL;
			pCaulk = QERApp_Shader_ForName( SHADER_CAULK );

			for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
			{
				if ( pTerrainShader == NULL ) {
					for ( f = b->brush_faces; f != NULL; f = f->next )
						if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) {
							pTerrainShader = f->pShader;
						}
				}

				if ( pTerrainShader ) {
					for ( f = b->brush_faces; f != NULL; f = f->next )
					{
						if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) { // not caulk
							Face_SetShader( f, pTerrainShader->getName() );
						}
						else{
							Face_SetShader( f, pCaulk->getName() );
						}
					}
				}
				else{
					Sys_FPrintf( SYS_WRN, "WARNING: no terrain shader found for brush\n" );
				}
			}
		}
#endif

#define PATCH_HACK
#ifdef PATCH_HACK
		for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
		{
			// patch hack, to be removed when dependency on brush_faces is removed
			if ( b->patchBrush ) {
				Patch_CalcBounds( b->pPatch, mins, maxs );
				for ( int i = 0; i < 3; i++ )
				{
					if ( (int)mins[i] == (int)maxs[i] ) {
						mins[i] -= 4;
						maxs[i] += 4;
					}
				}
				Brush_Resize( b, mins, maxs );
				Brush_Build( b );
			}
		}
#endif
		// add brush for fixedsize entity
		if ( e->eclass->fixedsize ) {
			vec3_t mins, maxs;
			VectorAdd( e->eclass->mins, e->origin, mins );
			VectorAdd( e->eclass->maxs, e->origin, maxs );
			b = Brush_Create( mins, maxs, &e->eclass->texdef );
			Entity_LinkBrush( e, b );
			Brush_Build( b );
		}

		for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
			Brush_AddToList( b, pBrushList );

		if ( strcmp( e->eclass->name, "worldspawn" ) == 0 ) {
			if ( world_entity ) {
				while ( e->brushes.onext != &e->brushes )
				{
					b = e->brushes.onext;
					Entity_UnlinkBrush( b );
					Entity_LinkBrush( world_entity, b );
				}
				Entity_Free( e );
			}
			else
			{
				world_entity = e;
			}
		}
		else if ( strcmp( e->eclass->name, "group_info" ) == 0 ) {
			// it's a group thing!
			Group_Add( e );
			Entity_Free( e );
		}
		else
		{
			// fix target/targetname collisions
			if ( ( g_PrefsDlg.m_bDoTargetFix ) && ( strcmp( ValueForKey( e, "target" ), "" ) != 0 ) ) {
				GPtrArray *t_ents = g_ptr_array_new();
				entity_t *e_target;
				const char *target = ValueForKey( e, "target" );
				qboolean bCollision = FALSE;

				// check the current map entities for an actual collision
				for ( e_target = entities.next; e_target != &entities; e_target = e_target->next )
				{
					if ( !strcmp( target, ValueForKey( e_target, "target" ) ) ) {
						bCollision = TRUE;
						// make sure the collision is not between two imported entities
						for ( j = 0; j < (int)new_ents->len; j++ )
						{
							if ( e_target == g_ptr_array_index( new_ents, j ) ) {
								bCollision = FALSE;
							}
						}
					}
				}

				// find the matching targeted entity(s)
				if ( bCollision ) {
					for ( j = num_ents - 1; j > 0; j-- )
					{
						e_target = (entity_t*)ents->GetAt( j );
						if ( e_target != NULL && e_target != e ) {
							const char *targetname = ValueForKey( e_target, "targetname" );
							if ( ( targetname != NULL ) && ( strcmp( target, targetname ) == 0 ) ) {
								g_ptr_array_add( t_ents, (gpointer)e_target );
							}
						}
					}
					if ( t_ents->len > 0 ) {
						// link the first to get a unique target/targetname
						Entity_Connect( e, (entity_t*)g_ptr_array_index( t_ents,0 ) );
						// set the targetname of the rest of them manually
						for ( j = 1; j < (int)t_ents->len; j++ )
							SetKeyValue( (entity_t*)g_ptr_array_index( t_ents, j ), "targetname", ValueForKey( e, "target" ) );
					}
					g_ptr_array_free( t_ents, FALSE );
				}
			}

			// add the entity to the end of the entity list
			Entity_AddToList( e, &entities );
			g_qeglobals.d_num_entities++;

			// keep a list of ents added to avoid testing collisions against them
			g_ptr_array_add( new_ents, (gpointer)e );
		}
	}
	g_ptr_array_free( new_ents, FALSE );

	ents->RemoveAll();

	g_qeglobals.bNeedConvert = false;
}
Ejemplo n.º 2
0
void BeginModel( void )
{
	bspModel_t	*mod;
	brush_t		*b;
	entity_t	*e;
	vec3_t		mins, maxs;
	vec3_t		lgMins, lgMaxs;		/* ydnar: lightgrid mins/maxs */
	parseMesh_t	*p;
	int			i;
	
	
	/* test limits */
	if( numBSPModels == MAX_MAP_MODELS )
		Error( "MAX_MAP_MODELS" );
	
	/* get model and entity */
	mod = &bspModels[ numBSPModels ];
	e = &entities[ mapEntityNum ];
	
	/* ydnar: lightgrid mins/maxs */
	ClearBounds( lgMins, lgMaxs );
	
	/* bound the brushes */
	ClearBounds( mins, maxs );
	for ( b = e->brushes; b; b = b->next )
	{
		/* ignore non-real brushes (origin, etc) */
		if( b->numsides == 0 )
			continue;
		AddPointToBounds( b->mins, mins, maxs );
		AddPointToBounds( b->maxs, mins, maxs );
		
		/* ydnar: lightgrid bounds */
		if( b->compileFlags & C_LIGHTGRID )
		{
			AddPointToBounds( b->mins, lgMins, lgMaxs );
			AddPointToBounds( b->maxs, lgMins, lgMaxs );
		}
	}
	
	/* bound patches */
	for( p = e->patches; p; p = p->next )
	{
		for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
			AddPointToBounds( p->mesh.verts[i].xyz, mins, maxs );
	}
	
	/* ydnar: lightgrid mins/maxs */
	if( lgMins[ 0 ] < 99999 )
	{
		/* use lightgrid bounds */
		VectorCopy( lgMins, mod->mins );
		VectorCopy( lgMaxs, mod->maxs );
	}
	else
	{
		/* use brush/patch bounds */
		VectorCopy( mins, mod->mins );
		VectorCopy( maxs, mod->maxs );
	}
	
	/* note size */
	Sys_FPrintf( SYS_VRB, "BSP bounds: { %f %f %f } { %f %f %f }\n", mins[ 0 ], mins[ 1 ], mins[ 2 ], maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
	Sys_FPrintf( SYS_VRB, "Lightgrid bounds: { %f %f %f } { %f %f %f }\n", lgMins[ 0 ], lgMins[ 1 ], lgMins[ 2 ], lgMaxs[ 0 ], lgMaxs[ 1 ], lgMaxs[ 2 ] );
	
	/* set firsts */
	mod->firstBSPSurface = numBSPDrawSurfaces;
	mod->firstBSPBrush = numBSPBrushes;
}
Ejemplo n.º 3
0
void SplitBrush( brush_t *brush, int planenum, brush_t **front, brush_t **back ){
	brush_t     *b[2];
	int i, j;
	winding_t   *w, *cw[2], *midwinding;
	plane_t     *plane, *plane2;
	side_t      *s, *cs;
	float d, d_front, d_back;


	*front = NULL;
	*back = NULL;
	plane = &mapplanes[planenum];

	// check all points
	d_front = d_back = 0;
	for ( i = 0 ; i < brush->numsides ; i++ )
	{
		w = brush->sides[i].winding;
		if ( !w ) {
			continue;
		}
		for ( j = 0 ; j < w->numpoints ; j++ )
		{
			d = DotProduct( w->p[j], plane->normal ) - plane->dist;
			if ( d > 0 && d > d_front ) {
				d_front = d;
			}
			if ( d < 0 && d < d_back ) {
				d_back = d;
			}
		}
	}

	if ( d_front < 0.1 ) { // PLANESIDE_EPSILON)
		// only on back
		*back = CopyBrush( brush );
		return;
	}

	if ( d_back > -0.1 ) { // PLANESIDE_EPSILON)
		// only on front
		*front = CopyBrush( brush );
		return;
	}

	// create a new winding from the split plane
	w = BaseWindingForPlane( plane->normal, plane->dist );
	for ( i = 0 ; i < brush->numsides && w ; i++ )
	{
		plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
		ChopWindingInPlace( &w, plane2->normal, plane2->dist, 0 ); // PLANESIDE_EPSILON);
	}

	if ( !w || WindingIsTiny( w ) ) { // the brush isn't really split
		int side;

		side = BrushMostlyOnSide( brush, plane );
		if ( side == PSIDE_FRONT ) {
			*front = CopyBrush( brush );
		}
		if ( side == PSIDE_BACK ) {
			*back = CopyBrush( brush );
		}
		return;
	}

	if ( WindingIsHuge( w ) ) {
		Sys_FPrintf( SYS_VRB,"WARNING: huge winding\n" );
	}

	midwinding = w;

	// split it for real

	for ( i = 0 ; i < 2 ; i++ )
	{
		b[i] = AllocBrush( brush->numsides + 1 );
		memcpy( b[i], brush, sizeof( brush_t ) - sizeof( brush->sides ) );
		b[i]->numsides = 0;
		b[i]->next = NULL;
		b[i]->original = brush->original;
	}

	// split all the current windings

	for ( i = 0 ; i < brush->numsides ; i++ )
	{
		s = &brush->sides[i];
		w = s->winding;
		if ( !w ) {
			continue;
		}
		/* strict, in parallel case we get the face back because it also is the midwinding */
		ClipWindingEpsilonStrict( w, plane->normal, plane->dist,
							0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1] );
		for ( j = 0 ; j < 2 ; j++ )
		{
			if ( !cw[j] ) {
				continue;
			}
			cs = &b[j]->sides[b[j]->numsides];
			b[j]->numsides++;
			*cs = *s;
			cs->winding = cw[j];
		}
	}


	// see if we have valid polygons on both sides
	for ( i = 0 ; i < 2 ; i++ )
	{
		if ( b[i]->numsides < 3 || !BoundBrush( b[i] ) ) {
			if ( b[i]->numsides >= 3 ) {
				Sys_FPrintf( SYS_VRB,"bogus brush after clip\n" );
			}
			FreeBrush( b[i] );
			b[i] = NULL;
		}
	}

	if ( !( b[0] && b[1] ) ) {
		if ( !b[0] && !b[1] ) {
			Sys_FPrintf( SYS_VRB,"split removed brush\n" );
		}
		else{
			Sys_FPrintf( SYS_VRB,"split not on both sides\n" );
		}
		if ( b[0] ) {
			FreeBrush( b[0] );
			*front = CopyBrush( brush );
		}
		if ( b[1] ) {
			FreeBrush( b[1] );
			*back = CopyBrush( brush );
		}
		return;
	}

	// add the midwinding to both sides
	for ( i = 0 ; i < 2 ; i++ )
	{
		cs = &b[i]->sides[b[i]->numsides];
		b[i]->numsides++;

		cs->planenum = planenum ^ i ^ 1;
		cs->shaderInfo = NULL;
		if ( i == 0 ) {
			cs->winding = CopyWinding( midwinding );
		}
		else{
			cs->winding = midwinding;
		}
	}

	{
		vec_t v1;
		int i;


		for ( i = 0 ; i < 2 ; i++ )
		{
			v1 = BrushVolume( b[i] );
			if ( v1 < 1.0 ) {
				FreeBrush( b[i] );
				b[i] = NULL;
				//			Sys_FPrintf (SYS_VRB,"tiny volume after clip\n");
			}
		}
	}

	*front = b[0];
	*back = b[1];
}
Ejemplo n.º 4
0
void PatchMapDrawSurfs( entity_t *e )
{
	int						i, j, k, l, c1, c2;
	parseMesh_t				*pm;
	parseMesh_t				*check, *scan;
	mapDrawSurface_t		*ds;
	int						patchCount, groupCount;
	bspDrawVert_t			*v1, *v2;
	vec3_t					bounds[ 2 ];
	byte					*bordering;
	
	/* ydnar: mac os x fails with these if not static */
	MAC_STATIC parseMesh_t	*meshes[ MAX_MAP_DRAW_SURFS ];
	MAC_STATIC qboolean		grouped[ MAX_MAP_DRAW_SURFS ];
	MAC_STATIC byte			group[ MAX_MAP_DRAW_SURFS ];
	
	
	/* note it */
	Sys_FPrintf( SYS_VRB, "--- PatchMapDrawSurfs ---\n" );

	/* fetch patches from the entity */
	patchCount = 0;
	for ( pm = e->patches ; pm ; pm = pm->next  ) 
	{
		meshes[patchCount] = pm;
		patchCount++;
	}

	if ( !patchCount ) 
		return;

	bordering = (byte *)safe_malloc( patchCount * patchCount );
	memset( bordering, 0, patchCount * patchCount );

	// build the bordering matrix
	for ( k = 0 ; k < patchCount ; k++ ) 
	{
		bordering[k*patchCount+k] = 1;

		for ( l = k+1 ; l < patchCount ; l++ ) 
		{
			check = meshes[k];
			scan = meshes[l];
			c1 = scan->mesh.width * scan->mesh.height;
			v1 = scan->mesh.verts;

			for ( i = 0 ; i < c1 ; i++, v1++ ) 
			{
				c2 = check->mesh.width * check->mesh.height;
				v2 = check->mesh.verts;
				for ( j = 0 ; j < c2 ; j++, v2++ ) 
				{
					if ( fabs( v1->xyz[0] - v2->xyz[0] ) < 1.0
						&& fabs( v1->xyz[1] - v2->xyz[1] ) < 1.0
						&& fabs( v1->xyz[2] - v2->xyz[2] ) < 1.0 ) {
						break;
					}
				}
				if ( j != c2 ) {
					break;
				}
			}
			if ( i != c1 ) 
			{
				// we have a connection
				bordering[k*patchCount+l] =
				bordering[l*patchCount+k] = 1;
			} else 
			{
				// no connection
				bordering[k*patchCount+l] =
				bordering[l*patchCount+k] = 0;
			}

		}
	}

	/* build groups */
	memset( grouped, 0, patchCount );
	groupCount = 0;
	for ( i = 0; i < patchCount; i++ )
	{
		/* get patch */
		scan = meshes[ i ];
		
		/* start a new group */
		if( !grouped[ i ] )
			groupCount++;
		
		/* recursively find all patches that belong in the same group */
		memset( group, 0, patchCount );
		GrowGroup_r( scan, i, patchCount, meshes, bordering, group );
		
		/* bound them */
		ClearBounds( bounds[ 0 ], bounds[ 1 ] );
		for( j = 0; j < patchCount; j++ )
		{
			if ( group[ j ] )
			{
				grouped[ j ] = qtrue;
				check = meshes[ j ];
				c1 = check->mesh.width * check->mesh.height;
				v1 = check->mesh.verts;
				for( k = 0; k < c1; k++, v1++ )
					AddPointToBounds( v1->xyz, bounds[ 0 ], bounds[ 1 ] );
			}
		}
		
		/* debug code */
		//%	Sys_Printf( "Longest curve: %f Iterations: %d\n", scan->longestCurve, scan->maxIterations );
		
		/* create drawsurf */
		scan->grouped = qtrue;
		ds = DrawSurfaceForMesh( e, scan, NULL );	/* ydnar */
		VectorCopy( bounds[ 0 ], ds->bounds[ 0 ] );
		VectorCopy( bounds[ 1 ], ds->bounds[ 1 ] );
	}
	
	/* emit some statistics */
	Sys_FPrintf( SYS_VRB, "%9d patches\n", patchCount );
	Sys_FPrintf( SYS_VRB, "%9d patch LOD groups\n", groupCount );
}
Ejemplo n.º 5
0
void LoadPNGBuffer(byte * data, byte ** pic, int *width, int *height)
{
	int             bit_depth;
	int             color_type;
	png_uint_32     w;
	png_uint_32     h;
	unsigned int    row;
	size_t          rowbytes;
	png_infop       info;
	png_structp     png;
	png_bytep      *row_pointers;
	byte           *out;
	int             size;
	byte            alphaByte = 255;

	// load png
//  size = ri.FS_ReadFile(name, (void **)&data);

	if(!data)
		return;

	//png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_user_error_fn, png_user_warning_fn);

	if(!png)
	{
		Sys_FPrintf(SYS_WRN, "LoadPNGBuffer: png_create_write_struct() failed\n");
		//free(data);
		return;
	}

	// allocate/initialize the memory for image information.  REQUIRED
	info = png_create_info_struct(png);
	if(!info)
	{
		Sys_FPrintf(SYS_WRN, "LoadPNGBuffer: png_create_info_struct() failed\n");
		//free(data);
		png_destroy_read_struct(&png, (png_infopp) NULL, (png_infopp) NULL);
		return;
	}

	//
	// Set error handling if you are using the setjmp/longjmp method (this is
	// the normal method of doing things with libpng).  REQUIRED unless you
	// set up your own error handlers in the png_create_read_struct() earlier.
	//
	if(setjmp(png_jmpbuf(png)))
	{
		// if we get here, we had a problem reading the file
		Sys_FPrintf(SYS_WRN, "LoadPNGBuffer: first exception handler called\n");
		//free(data);
		png_destroy_read_struct(&png, (png_infopp) & info, (png_infopp) NULL);
		return;
	}

	//png_set_write_fn(png, buffer, png_write_data, png_flush_data);
	png_set_read_fn(png, data, png_read_data);

	png_set_sig_bytes(png, 0);

	// The call to png_read_info() gives us all of the information from the
	// PNG file before the first IDAT (image data chunk).  REQUIRED
	png_read_info(png, info);

	// get picture info
	png_get_IHDR(png, info, (png_uint_32 *) & w, (png_uint_32 *) & h, &bit_depth, &color_type, NULL, NULL, NULL);

	// tell libpng to strip 16 bit/color files down to 8 bits/color
	png_set_strip_16(png);

	// expand paletted images to RGB triplets
	if(color_type & PNG_COLOR_MASK_PALETTE)
		png_set_expand(png);

	// expand gray-scaled images to RGB triplets
	if(!(color_type & PNG_COLOR_MASK_COLOR))
		png_set_gray_to_rgb(png);

	// expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel
	//if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
	//  png_set_gray_1_2_4_to_8(png);

	// expand paletted or RGB images with transparency to full alpha channels
	// so the data will be available as RGBA quartets
	if(png_get_valid(png, info, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha(png);

	// if there is no alpha information, fill with alphaByte
	if(!(color_type & PNG_COLOR_MASK_ALPHA))
		png_set_filler(png, alphaByte, PNG_FILLER_AFTER);

	// expand pictures with less than 8bpp to 8bpp
	if(bit_depth < 8)
		png_set_packing(png);

	// update structure with the above settings
	png_read_update_info(png, info);

	// allocate the memory to hold the image
	*width = w;
	*height = h;
	*pic = out = (byte *) safe_malloc(w * h * 4);

	row_pointers = (png_bytep *) safe_malloc(sizeof(png_bytep) * h);

	// set a new exception handler
	if(setjmp(png_jmpbuf(png)))
	{
		Sys_FPrintf(SYS_WRN, "LoadPNGBuffer: second exception handler called\n");
		free(row_pointers);
		//free(data);
		png_destroy_read_struct(&png, (png_infopp) & info, (png_infopp) NULL);
		return;
	}

	rowbytes = png_get_rowbytes(png, info);

	for(row = 0; row < h; row++)
		row_pointers[row] = (png_bytep) (out + (row * 4 * w));

	// read image data
	png_read_image(png, row_pointers);

	// read rest of file, and get additional chunks in info
	png_read_end(png, info);

	// clean up after the read, and free any memory allocated
	png_destroy_read_struct(&png, &info, (png_infopp) NULL);

	free(row_pointers);
	//free(data);
}
Ejemplo n.º 6
0
Archivo: bsp.c Proyecto: Teivaz/nebula2
void ProcessWorldModel( void )
{
    int            i, s;
    entity_t    *e;
    tree_t        *tree;
    face_t        *faces;
    qboolean    ignoreLeaks, leaked;
    xmlNodePtr    polyline, leaknode;
    char        level[ 2 ], shader[ 1024 ];
    const char    *value;
    
    
    /* sets integer blockSize from worldspawn "_blocksize" key if it exists */
    value = ValueForKey( &entities[ 0 ], "_blocksize" );
    if( value[ 0 ] == '\0' )
        value = ValueForKey( &entities[ 0 ], "blocksize" );
    if( value[ 0 ] == '\0' )
        value = ValueForKey( &entities[ 0 ], "chopsize" );    /* sof2 */
    if( value[ 0 ] != '\0' )
    {
        /* scan 3 numbers */
        s = sscanf( value, "%d %d %d", &blockSize[ 0 ], &blockSize[ 1 ], &blockSize[ 2 ] );
        
        /* handle legacy case */
        if( s == 1 )
        {
            blockSize[ 1 ] = blockSize[ 0 ];
            blockSize[ 2 ] = blockSize[ 0 ];
        }
    }
    Sys_Printf( "block size = { %d %d %d }\n", blockSize[ 0 ], blockSize[ 1 ], blockSize[ 2 ] );
    
    /* sof2: ignore leaks? */
    value = ValueForKey( &entities[ 0 ], "_ignoreleaks" );    /* ydnar */
    if( value[ 0 ] == '\0' )
        value = ValueForKey( &entities[ 0 ], "ignoreleaks" );
    if( value[ 0 ] == '1' )
        ignoreLeaks = qtrue;
    else
        ignoreLeaks = qfalse;
    
    /* begin worldspawn model */
    BeginModel();
    e = &entities[ 0 ];
    e->firstDrawSurf = 0;
    
    /* ydnar: gs mods */
    ClearMetaTriangles();

    /* check for patches with adjacent edges that need to lod together */
    PatchMapDrawSurfs( e );

    /* build an initial bsp tree using all of the sides of all of the structural brushes */
    faces = MakeStructuralBSPFaceList( entities[ 0 ].brushes );
    tree = FaceBSP( faces );
    MakeTreePortals( tree );
    FilterStructuralBrushesIntoTree( e, tree );
    
    /* see if the bsp is completely enclosed */
    if( FloodEntities( tree ) || ignoreLeaks )
    {
        /* rebuild a better bsp tree using only the sides that are visible from the inside */
        FillOutside( tree->headnode );

        /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */
        ClipSidesIntoTree( e, tree );
        
        /* build a visible face tree */
        faces = MakeVisibleBSPFaceList( entities[ 0 ].brushes );
        FreeTree( tree );
        tree = FaceBSP( faces );
        MakeTreePortals( tree );
        FilterStructuralBrushesIntoTree( e, tree );
        leaked = qfalse;
        
        /* ydnar: flood again for skybox */
        if( skyboxPresent )
            FloodEntities( tree );
    }
    else
    {
        Sys_FPrintf( SYS_NOXML, "**********************\n" );
        Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" );
        Sys_FPrintf( SYS_NOXML, "**********************\n" );
        polyline = LeakFile( tree );
        leaknode = xmlNewNode( NULL, "message" );
        xmlNodeSetContent( leaknode, "MAP LEAKED\n" );
        xmlAddChild( leaknode, polyline );
        level[0] = (int) '0' + SYS_ERR;
        level[1] = 0;
        xmlSetProp( leaknode, "level", (char*) &level );
        xml_SendNode( leaknode );
        if( leaktest )
        {
            Sys_Printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n");
            exit( 0 );
        }
        leaked = qtrue;
        
        /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */
        ClipSidesIntoTree( e, tree );
    }
    
    /* save out information for visibility processing */
    NumberClusters( tree );
    if( !leaked )
        WritePortalFile( tree );
    
    /* flood from entities */
    FloodAreas( tree );
    
    /* create drawsurfs for triangle models */
    AddTriangleModels( e );
    
    /* create drawsurfs for surface models */
    AddEntitySurfaceModels( e );
    
    /* generate bsp brushes from map brushes */
    EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes );
    
    /* add references to the detail brushes */
    FilterDetailBrushesIntoTree( e, tree );
    
    /* drawsurfs that cross fog boundaries will need to be split along the fog boundary */
    if( !nofog )
        FogDrawSurfaces( e );
    
    /* subdivide each drawsurf as required by shader tesselation */
    if( !nosubdivide )
        SubdivideFaceSurfaces( e, tree );
    
    /* add in any vertexes required to fix t-junctions */
    if( !notjunc )
        FixTJunctions( e );
    
    /* ydnar: classify the surfaces */
    ClassifyEntitySurfaces( e );
    
    /* ydnar: project decals */
    MakeEntityDecals( e );
    
    /* ydnar: meta surfaces */
    MakeEntityMetaTriangles( e );
    SmoothMetaTriangles();
    FixMetaTJunctions();
    MergeMetaTriangles();
    
    /* ydnar: debug portals */
    if( debugPortals )
        MakeDebugPortalSurfs( tree );
    
    /* ydnar: fog hull */
    value = ValueForKey( &entities[ 0 ], "_foghull" );
    if( value[ 0 ] != '\0' )
    {
        sprintf( shader, "textures/%s", value );
        MakeFogHullSurfs( e, tree, shader );
    }
    
    /* ydnar: bug 645: do flares for lights */
    for( i = 0; i < numEntities && emitFlares; i++ )
    {
        entity_t    *light, *target;
        const char    *value, *flareShader;
        vec3_t        origin, targetOrigin, normal, color;
        int            lightStyle;
        
        
        /* get light */
        light = &entities[ i ];
        value = ValueForKey( light, "classname" );
        if( !strcmp( value, "light" ) )
        {
            /* get flare shader */
            flareShader = ValueForKey( light, "_flareshader" );
            value = ValueForKey( light, "_flare" );
            if( flareShader[ 0 ] != '\0' || value[ 0 ] != '\0' )
            {
                /* get specifics */
                GetVectorForKey( light, "origin", origin );
                GetVectorForKey( light, "_color", color );
                lightStyle = IntForKey( light, "_style" );
                if( lightStyle == 0 )
                    lightStyle = IntForKey( light, "style" );
                
                /* handle directional spotlights */
                value = ValueForKey( light, "target" );
                if( value[ 0 ] != '\0' )
                {
                    /* get target light */
                    target = FindTargetEntity( value );
                    if( target != NULL )
                    {
                        GetVectorForKey( target, "origin", targetOrigin );
                        VectorSubtract( targetOrigin, origin, normal );
                        VectorNormalize( normal, normal );
                    }
                }
                else
                    //%    VectorClear( normal );
                    VectorSet( normal, 0, 0, -1 );
                
                /* create the flare surface (note shader defaults automatically) */
                DrawSurfaceForFlare( mapEntityNum, origin, normal, color, (char*) flareShader, lightStyle );
            }
        }
    }
    
    /* add references to the final drawsurfs in the apropriate clusters */
    FilterDrawsurfsIntoTree( e, tree );
    
    /* match drawsurfaces back to original brushsides (sof2) */
    FixBrushSides( e );
    
    /* finish */
    EndModel( e, tree->headnode );
    FreeTree( tree );
}
Ejemplo n.º 7
0
void InitPaths( int *argc, char **argv )
{
	int		i, j, k, len, len2;
	char	temp[ MAX_OS_PATH ];
	
	
	/* note it */
	Sys_FPrintf( SYS_VRB, "--- InitPaths ---\n" );
	
	/* get the install path for backup */
	LokiInitPaths( argv[ 0 ] );
	
	/* set game to default (q3a) */
	game = &games[ 0 ];
	numBasePaths = 0;
	numGamePaths = 0;
	
	/* parse through the arguments and extract those relevant to paths */
	for( i = 0; i < *argc; i++ )
	{
		/* check for null */
		if( argv[ i ] == NULL )
			continue;
		
		/* -game */
		if( strcmp( argv[ i ], "-game" ) == 0 )
		{
			if( ++i >= *argc )
				Error( "Out of arguments: No game specified after %s", argv[ i - 1 ] );
			argv[ i - 1 ] = NULL;
			game = GetGame( argv[ i ] );
			if( game == NULL )
				game = &games[ 0 ];
			argv[ i ] = NULL;
		}

		/* -fs_forbiddenpath */
		else if( strcmp( argv[ i ], "-fs_forbiddenpath" ) == 0 )
		{
			if( ++i >= *argc )
				Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
			argv[ i - 1 ] = NULL;
			if(g_numForbiddenDirs < VFS_MAXDIRS)
			{
				strncpy(g_strForbiddenDirs[g_numForbiddenDirs], argv[i], PATH_MAX);
				g_strForbiddenDirs[g_numForbiddenDirs][PATH_MAX] = 0;
				++g_numForbiddenDirs;
			}
			argv[ i ] = NULL;
		}

		/* -fs_basepath */
		else if( strcmp( argv[ i ], "-fs_basepath" ) == 0 )
		{
			if( ++i >= *argc )
				Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
			argv[ i - 1 ] = NULL;
			AddBasePath( argv[ i ] );
			argv[ i ] = NULL;
		}
		
		/* -fs_game */
		else if( strcmp( argv[ i ], "-fs_game" ) == 0 )
		{
			if( ++i >= *argc )
				Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
			argv[ i - 1 ] = NULL;
			AddGamePath( argv[ i ] );
			argv[ i ] = NULL;
		}
		
		/* -fs_home */
		else if( strcmp( argv[ i ], "-fs_home" ) == 0 )
		{
			if( ++i >= *argc )
				Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
			argv[ i - 1 ] = NULL;
			homePath = argv[i];
			argv[ i ] = NULL;
		}
		
		/* -fs_homebase */
		else if( strcmp( argv[ i ], "-fs_homebase" ) == 0 )
		{
			if( ++i >= *argc )
				Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
			argv[ i - 1 ] = NULL;
			homeBasePath = argv[i];
			argv[ i ] = NULL;
		}

		/* -fs_homepath - sets both of them */
		else if( strcmp( argv[ i ], "-fs_homepath" ) == 0 )
		{
			if( ++i >= *argc )
				Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
			argv[ i - 1 ] = NULL;
			homePath = argv[i];
			homeBasePath = ".";
			argv[ i ] = NULL;
		}
	}
	
	/* remove processed arguments */
	for( i = 0, j = 0, k = 0; i < *argc && j < *argc; i++, j++ )
	{
		for( ; j < *argc && argv[ j ] == NULL; j++ );
		argv[ i ] = argv[ j ];
		if( argv[ i ] != NULL )
			k++;
	}
	*argc = k;
	
	/* add standard game path */
	AddGamePath( game->gamePath );
	
	/* if there is no base path set, figure it out */
	if( numBasePaths == 0 )
	{
		/* this is another crappy replacement for SetQdirFromPath() */
		len2 = strlen( game->magic );
		for( i = 0; i < *argc && numBasePaths == 0; i++ )
		{
			/* extract the arg */
			strcpy( temp, argv[ i ] );
			CleanPath( temp );
			len = strlen( temp );
			Sys_FPrintf( SYS_VRB, "Searching for \"%s\" in \"%s\" (%d)...\n", game->magic, temp, i );
			
			/* this is slow, but only done once */
			for( j = 0; j < (len - len2); j++ )
			{
				/* check for the game's magic word */
				if( Q_strncasecmp( &temp[ j ], game->magic, len2 ) == 0 )
				{
					/* now find the next slash and nuke everything after it */
					while( temp[ ++j ] != '/' && temp[ j ] != '\0' );
					temp[ j ] = '\0';
					
					/* add this as a base path */
					AddBasePath( temp );
					break;
				}
			}
		}
		
		/* add install path */
		if( numBasePaths == 0 )
			AddBasePath( installPath );
		
		/* check again */
		if( numBasePaths == 0 )
			Error( "Failed to find a valid base path." );
	}
	
	/* this only affects unix */
	if(homeBasePath)
		AddHomeBasePath( homeBasePath );
	else
		AddHomeBasePath( game->homeBasePath );
	
	/* initialize vfs paths */
	if( numBasePaths > MAX_BASE_PATHS )
		numBasePaths = MAX_BASE_PATHS;
	if( numGamePaths > MAX_GAME_PATHS )
		numGamePaths = MAX_GAME_PATHS;
	
	/* walk the list of game paths */
	for( j = 0; j < numGamePaths; j++ )
	{
		/* walk the list of base paths */
		for( i = 0; i < numBasePaths; i++ )
		{
			/* create a full path and initialize it */
			sprintf( temp, "%s/%s/", basePaths[ i ], gamePaths[ j ] );
			vfsInitDirectory( temp );
		}
	}
	
	/* done */
	Sys_Printf( "\n" );
}
Ejemplo n.º 8
0
qboolean FloodEntities( tree_t *tree )
{
    int			i, s;
    vec3_t		origin, offset, scale, angles;
    qboolean	r, inside, tripped, skybox;
    node_t		*headnode;
    entity_t	*e;
    const char	*value;


    headnode = tree->headnode;
    Sys_FPrintf( SYS_VRB,"--- FloodEntities ---\n" );
    inside = qfalse;
    tree->outside_node.occupied = 0;

    tripped = qfalse;
    c_floodedleafs = 0;
    for( i = 1; i < numEntities; i++ )
    {
        /* get entity */
        e = &entities[ i ];

        /* get origin */
        GetVectorForKey( e, "origin", origin );
        if( VectorCompare( origin, vec3_origin ) )
            continue;

        /* handle skybox entities */
        value = ValueForKey( e, "classname" );
        if( !Q_stricmp( value, "_skybox" ) )
        {
            skybox = qtrue;
            skyboxPresent = qtrue;

            /* invert origin */
            VectorScale( origin, -1.0f, offset );

            /* get scale */
            VectorSet( scale, 64.0f, 64.0f, 64.0f );
            value = ValueForKey( e, "_scale" );
            if( value[ 0 ] != '\0' )
            {
                s = sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] );
                if( s == 1 )
                {
                    scale[ 1 ] = scale[ 0 ];
                    scale[ 2 ] = scale[ 0 ];
                }
            }

            /* get "angle" (yaw) or "angles" (pitch yaw roll) */
            VectorClear( angles );
            angles[ 2 ] = FloatForKey( e, "angle" );
            value = ValueForKey( e, "angles" );
            if( value[ 0 ] != '\0' )
                sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] );

            /* set transform matrix (thanks spog) */
            m4x4_identity( skyboxTransform );
            m4x4_pivoted_transform_by_vec3( skyboxTransform, offset, angles, eXYZ, scale, origin );
        }
        else
            skybox = qfalse;

        /* nudge off floor */
        origin[ 2 ] += 1;

        /* debugging code */
        //%	if( i == 1 )
        //%		origin[ 2 ] += 4096;

        /* find leaf */
        r = PlaceOccupant( headnode, origin, e, skybox );
        if( r )
            inside = qtrue;
        if( (!r || tree->outside_node.occupied) && !tripped )
        {
            xml_Select( "Entity leaked", e->mapEntityNum, 0, qfalse );
            tripped = qtrue;
        }
    }

    Sys_FPrintf( SYS_VRB, "%9d flooded leafs\n", c_floodedleafs );

    if( !inside )
        Sys_FPrintf( SYS_VRB, "no entities in open -- no filling\n" );
    else if( tree->outside_node.occupied )
        Sys_FPrintf( SYS_VRB, "entity reached from outside -- no filling\n" );

    return (qboolean) (inside && !tree->outside_node.occupied);
}
Ejemplo n.º 9
0
/*
=============
ChopWindingInPlaceAccu
=============
*/
void ChopWindingInPlaceAccu(winding_accu_t **inout, vec3_t normal, vec_t dist, vec_t crudeEpsilon)
{
	vec_accu_t	fineEpsilon;
	winding_accu_t	*in;
	int		counts[3];
	int		i, j;
	vec_accu_t	dists[MAX_POINTS_ON_WINDING + 1];
	int		sides[MAX_POINTS_ON_WINDING + 1];
	int		maxpts;
	winding_accu_t	*f;
	vec_accu_t	*p1, *p2;
	vec_accu_t	w;
	vec3_accu_t	mid, normalAccu;

	// We require at least a very small epsilon.  It's a good idea for several reasons.
	// First, we will be dividing by a potentially very small distance below.  We don't
	// want that distance to be too small; otherwise, things "blow up" with little accuracy
	// due to the division.  (After a second look, the value w below is in range (0,1), but
	// graininess problem remains.)  Second, Having minimum epsilon also prevents the following
	// situation.  Say for example we have a perfect octagon defined by the input winding.
	// Say our chopping plane (defined by normal and dist) is essentially the same plane
	// that the octagon is sitting on.  Well, due to rounding errors, it may be that point
	// 1 of the octagon might be in front, point 2 might be in back, point 3 might be in
	// front, point 4 might be in back, and so on.  So we could end up with a very ugly-
	// looking chopped winding, and this might be undesirable, and would at least lead to
	// a possible exhaustion of MAX_POINTS_ON_WINDING.  It's better to assume that points
	// very very close to the plane are on the plane, using an infinitesimal epsilon amount.

	// Now, the original ChopWindingInPlace() function used a vec_t-based winding_t.
	// So this minimum epsilon is quite similar to casting the higher resolution numbers to
	// the lower resolution and comparing them in the lower resolution mode.  We explicitly
	// choose the minimum epsilon as something around the vec_t epsilon of one because we
	// want the resolution of vec_accu_t to have a large resolution around the epsilon.
	// Some of that leftover resolution even goes away after we scale to points far away.

	// Here is a further discussion regarding the choice of smallestEpsilonAllowed.
	// In the 32 float world (we can assume vec_t is that), the "epsilon around 1.0" is
	// 0.00000011921.  In the 64 bit float world (we can assume vec_accu_t is that), the
	// "epsilon around 1.0" is 0.00000000000000022204.  (By the way these two epsilons
	// are defined as VEC_SMALLEST_EPSILON_AROUND_ONE VEC_ACCU_SMALLEST_EPSILON_AROUND_ONE
	// respectively.)  If you divide the first by the second, you get approximately
	// 536,885,246.  Dividing that number by 200,000 (a typical base winding coordinate)
	// gives 2684.  So in other words, if our smallestEpsilonAllowed was chosen as exactly
	// VEC_SMALLEST_EPSILON_AROUND_ONE, you would be guaranteed at least 2000 "ticks" in
	// 64-bit land inside of the epsilon for all numbers we're dealing with.

	static const vec_accu_t smallestEpsilonAllowed = ((vec_accu_t) VEC_SMALLEST_EPSILON_AROUND_ONE) * 0.5;
	if (crudeEpsilon < smallestEpsilonAllowed)	fineEpsilon = smallestEpsilonAllowed;
	else						fineEpsilon = (vec_accu_t) crudeEpsilon;

	in = *inout;
	counts[0] = counts[1] = counts[2] = 0;
	VectorCopyRegularToAccu(normal, normalAccu);

	for (i = 0; i < in->numpoints; i++)
	{
		dists[i] = DotProductAccu(in->p[i], normalAccu) - dist;
		if (dists[i] > fineEpsilon)		sides[i] = SIDE_FRONT;
		else if (dists[i] < -fineEpsilon)	sides[i] = SIDE_BACK;
		else					sides[i] = SIDE_ON;
		counts[sides[i]]++;
	}
	sides[i] = sides[0];
	dists[i] = dists[0];
	
	// I'm wondering if whatever code that handles duplicate planes is robust enough
	// that we never get a case where two nearly equal planes result in 2 NULL windings
	// due to the 'if' statement below.  TODO: Investigate this.
	if (!counts[SIDE_FRONT]) {
		FreeWindingAccu(in);
		*inout = NULL;
		return;
	}
	if (!counts[SIDE_BACK]) {
		return; // Winding is unmodified.
	}

	// NOTE: The least number of points that a winding can have at this point is 2.
	// In that case, one point is SIDE_FRONT and the other is SIDE_BACK.

	maxpts = counts[SIDE_FRONT] + 2; // We dynamically expand if this is too small.
	f = AllocWindingAccu(maxpts);

	for (i = 0; i < in->numpoints; i++)
	{
		p1 = in->p[i];

		if (sides[i] == SIDE_ON || sides[i] == SIDE_FRONT)
		{
			if (f->numpoints >= MAX_POINTS_ON_WINDING)
				Error("ChopWindingInPlaceAccu: MAX_POINTS_ON_WINDING");
			if (f->numpoints >= maxpts) // This will probably never happen.
			{
				Sys_FPrintf(SYS_VRB, "WARNING: estimate on chopped winding size incorrect (no problem)\n");
				f = CopyWindingAccuIncreaseSizeAndFreeOld(f);
				maxpts++;
			}
			VectorCopyAccu(p1, f->p[f->numpoints]);
			f->numpoints++;
			if (sides[i] == SIDE_ON) continue;
		}
		if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
		{
			continue;
		}
			
		// Generate a split point.
		p2 = in->p[((i + 1) == in->numpoints) ? 0 : (i + 1)];

		// The divisor's absolute value is greater than the dividend's absolute value.
		// w is in the range (0,1).
		w = dists[i] / (dists[i] - dists[i + 1]);

		for (j = 0; j < 3; j++)
		{
			// Avoid round-off error when possible.  Check axis-aligned normal.
			if (normal[j] == 1)		mid[j] = dist;
			else if (normal[j] == -1)	mid[j] = -dist;
			else				mid[j] = p1[j] + (w * (p2[j] - p1[j]));
		}
		if (f->numpoints >= MAX_POINTS_ON_WINDING)
			Error("ChopWindingInPlaceAccu: MAX_POINTS_ON_WINDING");
		if (f->numpoints >= maxpts) // This will probably never happen.
		{
			Sys_FPrintf(SYS_VRB, "WARNING: estimate on chopped winding size incorrect (no problem)\n");
			f = CopyWindingAccuIncreaseSizeAndFreeOld(f);
			maxpts++;
		}
		VectorCopyAccu(mid, f->p[f->numpoints]);
		f->numpoints++;
	}

	FreeWindingAccu(in);
	*inout = f;
}
Ejemplo n.º 10
0
void RadCreateDiffuseLights( void )
{
    /* startup */
    Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" );
    numDiffuseSurfaces = 0;
    numDiffuseLights = 0;
    numBrushDiffuseLights = 0;
    numTriangleDiffuseLights = 0;
    numPatchDiffuseLights = 0;
    numAreaLights = 0;
    
    /* hit every surface (threaded) */
    RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight );
    
    /* dump the lights generated to a file */
    if( dump )
    {
        char    dumpName[ 1024 ], ext[ 64 ];
        FILE    *file;
        light_t    *light;
        
        strcpy( dumpName, source );
        StripExtension( dumpName );
        sprintf( ext, "_bounce_%03d.map", iterations );
        strcat( dumpName, ext );
        file = fopen( dumpName, "wb" );
        Sys_Printf( "Writing %s...\n", dumpName );
        if( file )
        {
            for( light = lights; light; light = light->next )
            {
                fprintf( file,
                    "{\n"
                    "\"classname\" \"light\"\n"
                    "\"light\" \"%d\"\n"
                    "\"origin\" \"%.0f %.0f %.0f\"\n"
                    "\"_color\" \"%.3f %.3f %.3f\"\n"
                    "}\n",
                    
                    (int) light->add,
                    
                    light->origin[ 0 ],
                    light->origin[ 1 ],
                    light->origin[ 2 ],
                    
                    light->color[ 0 ],
                    light->color[ 1 ],
                    light->color[ 2 ] );
            }
            fclose( file );
        }
    }
    
    /* increment */
    iterations++;
    
    /* print counts */
    Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces );
    Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights );
    Sys_FPrintf( SYS_VRB, "%8d brush diffuse lights\n", numBrushDiffuseLights );
    Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights );
    Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights );
}
Ejemplo n.º 11
0
// send a node down the stream, add it to the document
void xml_SendNode (xmlNodePtr node)
{
  xmlBufferPtr xml_buf;
  char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
  // this index loops through the node buffer
  int pos = 0;
  int size;

  xmlAddChild( doc->children, node );

  if (brdcst_socket)
  {
    xml_buf = xmlBufferCreate();
    xmlNodeDump( xml_buf, doc, node, 0, 0 );

    // the XML node might be too big to fit in a single network message
    // l_net library defines an upper limit of MAX_NETMESSAGE
    // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe
    // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages
    while (pos < (int)xml_buf->use)
    {
      // what size are we gonna send now?
      (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10);
      //++timo just a debug thing
      if (size == MAX_NETMESSAGE - 10)
        Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n");
      memcpy( xmlbuf, xml_buf->content+pos, size);
      xmlbuf[size] = '\0';
      NMSG_Clear( &msg );
      NMSG_WriteString (&msg, xmlbuf );
      Net_Send(brdcst_socket, &msg );
      // now that the thing is sent prepare to loop again
      pos += size;
    }

#if 0
    // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
    // we will need to split into chunks
    // (we could also go lower level, in the end it's using send and receiv which are not size limited)
    //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
    //  there's some tweaking to do in l_net for that .. so let's give us a margin for now

    //++timo we need to handle the case of a buffer too big to fit in a single message
    // try without checks for now
    if (xml_buf->use > MAX_NETMESSAGE-10 )
    {
      // if we send that we are probably gonna break the stream at the other end..
      // and Error will call right there
      //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
      Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
      xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing
      Sys_FPrintf (SYS_NOXML, xml_buf->content);

    }

    size = xml_buf->use;
    memcpy( xmlbuf, xml_buf->content, size );
    xmlbuf[size] = '\0';
    NMSG_Clear( &msg );
    NMSG_WriteString (&msg, xmlbuf );
    Net_Send(brdcst_socket, &msg );
#endif

    xmlBufferFree( xml_buf );
  }  
}
Ejemplo n.º 12
0
/*
   ===========
   QE_LoadProject
   NOTE: rather than bumping "version", consider bumping "template_version" (see above)
   NOTE: when QE_LoadProject is called, the prefs are updated with path to the latest project and saved on disk
   ===========
 */
bool QE_LoadProject( const char *projectfile ){
	char buf[1024];
	xmlDocPtr doc;
	xmlNodePtr node, project;

	Sys_Printf( "Loading project file: \"%s\"\n", projectfile );
	doc = ParseXMLFile( projectfile, true );

	if ( doc == NULL ) {
		return false;
	}

	node = doc->children;
	while ( node != NULL && node->type != XML_DTD_NODE ) node = node->next;
	if ( node == NULL || strcmp( (char*)node->name, "project" ) != 0 ) {
		Sys_FPrintf( SYS_ERR, "ERROR: invalid file type\n" );
		return false;
	}

	while ( node->type != XML_ELEMENT_NODE ) node = node->next;
	// <project>
	project = node;

	if ( g_qeglobals.d_project_entity != NULL ) {
		Entity_Free( g_qeglobals.d_project_entity );
	}
	g_qeglobals.d_project_entity = Entity_Alloc();

	for ( node = project->children; node != NULL; node = node->next )
	{
		if ( node->type != XML_ELEMENT_NODE ) {
			continue;
		}

		// <key>
		ReplaceTemplates( buf, (char*)node->properties->next->children->content );

		SetKeyValue( g_qeglobals.d_project_entity, (char*)node->properties->children->content, buf );
	}

	xmlFreeDoc( doc );

	// project file version checking
	// add a version checking to avoid people loading later versions of the project file and bitching
	int ver = IntForKey( g_qeglobals.d_project_entity, "version" );
	if ( ver > PROJECT_VERSION ) {
		char strMsg[1024];
		sprintf( strMsg, "This is a version %d project file. This build only supports <=%d project files.\n"
						 "Please choose another project file or upgrade your version of Radiant.", ver, PROJECT_VERSION );
		gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK );
		// set the project file to nothing so we are sure we'll ask next time?
		g_PrefsDlg.m_strLastProject = "";
		g_PrefsDlg.SavePrefs();
		return false;
	}

	// set here some default project settings you need
	if ( strlen( ValueForKey( g_qeglobals.d_project_entity, "brush_primit" ) ) == 0 ) {
		SetKeyValue( g_qeglobals.d_project_entity, "brush_primit", "0" );
	}

	g_qeglobals.m_bBrushPrimitMode = IntForKey( g_qeglobals.d_project_entity, "brush_primit" );

	g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame;
	const char* str = ValueForKey( g_qeglobals.d_project_entity, "gamename" );
	if ( str[0] == '\0' ) {
		str = g_pGameDescription->mBaseGame.GetBuffer();
	}
	g_qeglobals.m_strHomeMaps += str;
	g_qeglobals.m_strHomeMaps += '/';

	// don't forget to create the dirs
	Q_mkdir( g_qeglobals.m_strHomeGame.GetBuffer(), 0775 );
	Q_mkdir( g_qeglobals.m_strHomeMaps.GetBuffer(), 0775 );

	// usefull for the log file and debuggin f****d up configurations from users:
	// output the basic information of the .qe4 project file
	// SPoG
	// all these paths should be unix format, with a trailing slash at the end
	// if not.. to debug, check that the project file paths are set up correctly
	Sys_Printf( "basepath    : %s\n", ValueForKey( g_qeglobals.d_project_entity, "basepath" ) );
	Sys_Printf( "entitypath  : %s\n", ValueForKey( g_qeglobals.d_project_entity, "entitypath" ) );


	// check whether user_project key exists..
	// if not, save the current project under a new name
	if ( ValueForKey( g_qeglobals.d_project_entity, "user_project" )[0] == '\0' ) {
		Sys_Printf( "Loaded a template project file\n" );

		// create the user_project key
		SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" );

		if ( IntForKey( g_qeglobals.d_project_entity, "version" ) != PROJECT_VERSION ) {
			char strMsg[2048];
			sprintf( strMsg,
					 "The template project '%s' has version %d. The editor binary is configured for version %d.\n"
					 "This indicates a problem in your setup.\n"
					 "I will keep going with this project till you fix this",
					 projectfile, IntForKey( g_qeglobals.d_project_entity, "version" ), PROJECT_VERSION );
			gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK );
		}

		// create the writable project file path
		strcpy( buf, g_qeglobals.m_strHomeGame.GetBuffer() );
		strcat( buf, g_pGameDescription->mBaseGame.GetBuffer() );
		strcat( buf, "/scripts/" );
		// while the filename is already in use, increment the number we add to the end
		int counter = 0;
		char pUser[PATH_MAX];
		while ( 1 )
		{
			sprintf( pUser, "%suser%d." PROJECT_FILETYPE, buf, counter );
			counter++;
			if ( access( pUser, R_OK ) != 0 ) {
				// this is the one
				strcpy( buf, pUser );
				break;
			}
		}
		// saving project will cause a save prefs
		g_PrefsDlg.m_strLastProject = buf;
		g_PrefsDlg.m_nLastProjectVer = IntForKey( g_qeglobals.d_project_entity, "version" );
		QE_SaveProject( buf );
	}
	else
	{
		// update preferences::LastProject with path of this successfully-loaded project
		// save preferences
		Sys_Printf( "Setting current project in prefs to \"%s\"\n", g_PrefsDlg.m_strLastProject.GetBuffer() );
		g_PrefsDlg.m_strLastProject = projectfile;
		g_PrefsDlg.SavePrefs();
	}

	return true;
}
Ejemplo n.º 13
0
/*
   ===========
   AddRegionBrushes
   a regioned map will have temp walls put up at the region boundary
   \todo TODO TTimo old implementation of region brushes
   we still add them straight in the worldspawn and take them out after the map is saved
   with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
   ===========
 */
void AddRegionBrushes( void ){
	vec3_t mins, maxs;
	int i;
	texdef_t td;

	if ( !region_active ) {
#ifdef _DEBUG
		Sys_FPrintf( SYS_WRN, "Unexpected AddRegionBrushes call.\n" );
#endif
		return;
	}

	memset( &td, 0, sizeof( td ) );
	td.SetName( SHADER_NOT_FOUND );

	// set mins
	VectorSet( mins, region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 );

	// vary maxs
	for ( i = 0; i < 3; i++ )
	{
		VectorSet( maxs, region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 );
		maxs[i] = region_mins[i];
		region_sides[i] = Brush_Create( mins, maxs, &td );
	}

	// set maxs
	VectorSet( maxs, region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 );

	// vary mins
	for ( i = 0; i < 3; i++ )
	{
		VectorSet( mins, region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 );
		mins[i] = region_maxs[i];
		region_sides[i + 3] = Brush_Create( mins, maxs, &td );
	}


	// this is a safe check, but it should not really happen anymore
	vec3_t vOrig;
	VectorSet( vOrig,
			   (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0],
			   (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1],
			   (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2] );

	for ( i = 0 ; i < 3 ; i++ )
	{
		if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) {
			Sys_FPrintf( SYS_ERR, "Camera is NOT in the region, it's likely that the region won't compile correctly\n" );
		}
	}

	// write the info_playerstart
	region_startpoint = Entity_Alloc();
	SetKeyValue( region_startpoint, "classname", "info_player_start" );
	region_startpoint->eclass = Eclass_ForName( "info_player_start", false );
	char sTmp[1024];
	sprintf( sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2] );
	SetKeyValue( region_startpoint, "origin", sTmp );
	sprintf( sTmp, "%d", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] );
	SetKeyValue( region_startpoint, "angle", sTmp );
	// empty array of children
	region_startpoint->pData = new CPtrArray;
}
Ejemplo n.º 14
0
/*
   ================
   Map_LoadFile
   ================
 */
void Map_LoadFile( const char *filename ){
	clock_t start, finish;
	double elapsed_time;
	start = clock();

	Sys_BeginWait();
	Select_Deselect();
	/*!
	   \todo FIXME TTimo why is this commented out?
	   stability issues maybe? or duplicate feature?
	   forcing to show the console during map load was a good thing IMO
	 */
	//SetInspectorMode(W_CONSOLE);
	Sys_Printf( "Loading map from %s\n", filename );

	Map_Free();
	//++timo FIXME: maybe even easier to have Group_Init called from Map_Free?
	Group_Init();
	g_qeglobals.d_num_entities = 0;
	g_qeglobals.d_parsed_brushes = 0;


	// cancel the map loading process
	// used when conversion between standard map format and BP format is required and the user cancels the process
	g_bCancel_Map_LoadFile = false;

	strcpy( currentmap, filename );

	g_bScreenUpdates = false; // leo: avoid redraws while loading the map (see fenris:1952)

	// prepare to let the map module do the parsing
	FileStream file;
	const char* type = strrchr( filename,'.' );
	if ( type != NULL ) {
		type++;
	}
	// NOTE TTimo opening has binary doesn't make a lot of sense
	// but opening as text confuses the scriptlib parser
	// this may be a problem if we "rb" and use the XML parser, might have an incompatibility
	if ( file.Open( filename, "rb" ) ) {
		Map_Import( &file, type );
	}
	else{
		Sys_FPrintf( SYS_ERR, "ERROR: failed to open %s for read\n", filename );
	}
	file.Close();

	g_bScreenUpdates = true;

	if ( g_bCancel_Map_LoadFile ) {
		Sys_Printf( "Map_LoadFile canceled\n" );
		Map_New();
		Sys_EndWait();
		return;
	}

	if ( !world_entity ) {
		Sys_Printf( "No worldspawn in map.\n" );
		Map_New();
		Sys_EndWait();
		return;
	}
	finish = clock();
	elapsed_time = (double)( finish - start ) / CLOCKS_PER_SEC;

	Sys_Printf( "--- LoadMapFile ---\n" );
	Sys_Printf( "%s\n", filename );

	Sys_Printf( "%5i brushes\n",  g_qeglobals.d_parsed_brushes );
	Sys_Printf( "%5i entities\n", g_qeglobals.d_num_entities );
	Sys_Printf( "%5.2f second(s) load time\n", elapsed_time );

	Sys_EndWait();

	Map_RestoreBetween();

	//
	// move the view to a start position
	//
	Map_StartPosition();

	Map_RegionOff();

	modified = false;
	Sys_SetTitle( filename );

	Texture_ShowInuse();
	QERApp_SortActiveShaders();

	Sys_UpdateWindows( W_ALL );
}
Ejemplo n.º 15
0
Archivo: fog.c Proyecto: 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);
}
Ejemplo n.º 16
0
Archivo: fog.c Proyecto: Elzair/q3map2
void FogDrawSurfaces( entity_t *e ){
	int i, j, k, fogNum;
	fog_t               *fog;
	mapDrawSurface_t    *ds;
	vec3_t mins, maxs;
	int fogged, numFogged;
	int numBaseDrawSurfs;


	/* note it */
	Sys_FPrintf( SYS_VRB, "----- FogDrawSurfs -----\n" );

	/* reset counters */
	numFogged = 0;
	numFogFragments = 0;

	/* walk fog list */
	for ( fogNum = 0; fogNum < numMapFogs; fogNum++ )
	{
		/* get fog */
		fog = &mapFogs[ fogNum ];

		/* clip each surface into this, but don't clip any of the resulting fragments to the same brush */
		numBaseDrawSurfs = numMapDrawSurfs;
		for ( i = 0; i < numBaseDrawSurfs; i++ )
		{
			/* get the drawsurface */
			ds = &mapDrawSurfs[ i ];

			/* no fog? */
			if ( ds->shaderInfo->noFog ) {
				continue;
			}

			/* global fog doesn't have a brush */
			if ( fog->brush == NULL ) {
				/* don't re-fog already fogged surfaces */
				if ( ds->fogNum >= 0 ) {
					continue;
				}
				fogged = 1;
			}
			else
			{
				/* find drawsurface bounds */
				ClearBounds( mins, maxs );
				for ( j = 0; j < ds->numVerts; j++ )
					AddPointToBounds( ds->verts[ j ].xyz, mins, maxs );

				/* check against the fog brush */
				for ( k = 0; k < 3; k++ )
				{
					if ( mins[ k ] > fog->brush->maxs[ k ] ) {
						break;
					}
					if ( maxs[ k ] < fog->brush->mins[ k ] ) {
						break;
					}
				}

				/* no intersection? */
				if ( k < 3 ) {
					continue;
				}

				/* ydnar: gs mods: handle the various types of surfaces */
				switch ( ds->type )
				{
				/* handle brush faces */
				case SURFACE_FACE:
					fogged = ChopFaceSurfaceByBrush( e, ds, fog->brush );
					break;

				/* handle patches */
				case SURFACE_PATCH:
					fogged = ChopPatchSurfaceByBrush( e, ds, fog->brush );
					break;

				/* handle triangle surfaces (fixme: split triangle surfaces) */
				case SURFACE_TRIANGLES:
				case SURFACE_FORCED_META:
				case SURFACE_META:
					fogged = 1;
					break;

				/* no fogging */
				default:
					fogged = 0;
					break;
				}
			}

			/* is this surface fogged? */
			if ( fogged ) {
				numFogged += fogged;
				ds->fogNum = fogNum;
			}
		}
	}

	/* emit some statistics */
	Sys_FPrintf( SYS_VRB, "%9d fog polygon fragments\n", numFogFragments );
	Sys_FPrintf( SYS_VRB, "%9d fog patch fragments\n", numFogPatchFragments );
	Sys_FPrintf( SYS_VRB, "%9d fogged drawsurfs\n", numFogged );
}
Ejemplo n.º 17
0
void CPortals::Load(){
	char buf[LINE_BUF + 1];

	memset( buf, 0, LINE_BUF + 1 );

	Purge();

	Sys_Printf( MSG_PREFIX "Loading portal file %s.\n", fn );

	FILE *in;

	in = fopen( fn, "rt" );

	if ( in == NULL ) {
		Sys_FPrintf( SYS_ERR, "ERROR - could not open file.\n" );

		return;
	}

	if ( !fgets( buf, LINE_BUF, in ) ) {
		fclose( in );

		Sys_FPrintf( SYS_ERR, "ERROR - File ended prematurely.\n" );

		return;
	}

	if ( strncmp( "PRT1", buf, 4 ) != 0 ) {
		fclose( in );

		Sys_FPrintf( SYS_ERR, "ERROR - File header indicates wrong file type (should be \"PRT1\").\n" );

		return;
	}

	if ( !fgets( buf, LINE_BUF, in ) ) {
		fclose( in );

		Sys_FPrintf( SYS_ERR, "ERROR - File ended prematurely.\n" );

		return;
	}

	sscanf( buf, "%u", &node_count );
/*
    if(node_count > 0xFFFF)
    {
        fclose(in);

        node_count = 0;

        Sys_FPrintf( SYS_ERR, "ERROR - Extreme number of nodes, aborting.\n");

        return;
    }
 */

	if ( !fgets( buf, LINE_BUF, in ) ) {
		fclose( in );

		node_count = 0;

		Sys_FPrintf( SYS_ERR, "ERROR - File ended prematurely.\n" );

		return;
	}

	sscanf( buf, "%u", &portal_count );

	if ( portal_count > 0xFFFF ) {
		fclose( in );

		portal_count = 0;
		node_count = 0;

		Sys_FPrintf( SYS_ERR, "ERROR - Extreme number of portals, aborting.\n" );

		return;
	}

	if ( portal_count < 0 ) {
		fclose( in );

		portal_count = 0;
		node_count = 0;

		Sys_FPrintf( SYS_ERR, "ERROR - number of portals equals 0, aborting.\n" );

		return;
	}

//	node = new CBspNode[node_count];
	portal = new CBspPortal[portal_count];
	portal_sort = new int[portal_count];

	unsigned int n;
	qboolean first = TRUE;
	unsigned test_vals_1, test_vals_2;

	hint_flags = FALSE;

	for ( n = 0; n < portal_count; )
	{
		if ( !fgets( buf, LINE_BUF, in ) ) {
			fclose( in );

			Purge();

			Sys_FPrintf( SYS_ERR, "ERROR - Could not find information for portal number %d of %d.\n", n + 1, portal_count );

			return;
		}

		if ( !portal[n].Build( buf ) ) {
			if ( first && sscanf( buf, "%d %d", &test_vals_1, &test_vals_2 ) == 1 ) { // skip additional counts of later data, not needed
				// We can count on hint flags being in the file
				hint_flags = TRUE;
				continue;
			}

			first = FALSE;

			fclose( in );

			Purge();

			Sys_FPrintf( SYS_ERR, "ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, portal_count );

			return;
		}

		n++;
	}

	fclose( in );

	Sys_Printf( "  %u portals read in.\n", node_count, portal_count );
}
Ejemplo n.º 18
0
Archivo: fog.c Proyecto: Elzair/q3map2
void CreateMapFogs( void ){
	int i;
	entity_t    *entity;
	brush_t     *brush;
	fog_t       *fog;
	vec3_t invFogDir;
	const char  *globalFog;


	/* skip? */
	if ( nofog ) {
		return;
	}

	/* note it */
	Sys_FPrintf( SYS_VRB, "--- CreateMapFogs ---\n" );

	/* walk entities */
	for ( i = 0; i < numEntities; i++ )
	{
		/* get entity */
		entity = &entities[ i ];

		/* walk entity brushes */
		for ( brush = entity->brushes; brush != NULL; brush = brush->next )
		{
			/* ignore non-fog brushes */
			if ( brush->contentShader->fogParms == qfalse ) {
				continue;
			}

			/* test limit */
			if ( numMapFogs >= MAX_MAP_FOGS ) {
				Error( "Exceeded MAX_MAP_FOGS (%d)", MAX_MAP_FOGS );
			}

			/* set up fog */
			fog = &mapFogs[ numMapFogs++ ];
			fog->si = brush->contentShader;
			fog->brush = brush;
			fog->visibleSide = -1;

			/* if shader specifies an explicit direction, then find a matching brush side with an opposed normal */
			if ( VectorLength( fog->si->fogDir ) ) {
				/* flip it */
				VectorScale( fog->si->fogDir, -1.0f, invFogDir );

				/* find the brush side */
				for ( i = 0; i < brush->numsides; i++ )
				{
					if ( VectorCompare( invFogDir, mapplanes[ brush->sides[ i ].planenum ].normal ) ) {
						fog->visibleSide = i;
						//%	Sys_Printf( "Brush num: %d Side num: %d\n", fog->brushNum, fog->visibleSide );
						break;
					}
				}
			}
		}
	}

	/* ydnar: global fog */
	globalFog = ValueForKey( &entities[ 0 ], "_fog" );
	if ( globalFog[ 0 ] == '\0' ) {
		globalFog = ValueForKey( &entities[ 0 ], "fog" );
	}
	if ( globalFog[ 0 ] != '\0' ) {
		/* test limit */
		if ( numMapFogs >= MAX_MAP_FOGS ) {
			Error( "Exceeded MAX_MAP_FOGS (%d) trying to add global fog", MAX_MAP_FOGS );
		}

		/* note it */
		Sys_FPrintf( SYS_VRB, "Map has global fog shader %s\n", globalFog );

		/* set up fog */
		fog = &mapFogs[ numMapFogs++ ];
		fog->si = ShaderInfoForShaderNull( globalFog );
		if ( fog->si == NULL ) {
			Error( "Invalid shader \"%s\" referenced trying to add global fog", globalFog );
		}
		fog->brush = NULL;
		fog->visibleSide = -1;

		/* set as default fog */
		defaultFogNum = numMapFogs - 1;

		/* mark all worldspawn brushes as fogged */
		for ( brush = entities[ 0 ].brushes; brush != NULL; brush = brush->next )
			ApplySurfaceParm( "fog", &brush->contentFlags, NULL, &brush->compileFlags );
	}

	/* emit some stats */
	Sys_FPrintf( SYS_VRB, "%9d fogs\n", numMapFogs );
}
Ejemplo n.º 19
0
void LeakFile(tree_t * tree)
#endif
{
	vec3_t          mid;
	FILE           *linefile;
	char            filename[1024];
	node_t         *node;
	int             count;

#if defined(USE_XML)
	xmlNodePtr      xml_node, point;
#endif

	if(!tree->outside_node.occupied)
	{
#if defined(USE_XML)
		return NULL;
#endif
	}

	Sys_FPrintf(SYS_VRB, "--- LeakFile ---\n");

	//
	// write the points to the file
	//
	sprintf(filename, "%s.lin", source);
	linefile = fopen(filename, "w");
	if(!linefile)
		Error("Couldn't open %s", filename);

#if defined(USE_XML)
	xml_node = xmlNewNode(NULL, "polyline");
#endif

	count = 0;
	node = &tree->outside_node;
	while(node->occupied > 1)
	{
		int             next;
		portal_t       *p, *nextportal = NULL; // STFU, compiler
		node_t         *nextnode = NULL; // STFU, compiler
		int             s;

		// find the best portal exit
		next = node->occupied;
		for(p = node->portals; p; p = p->next[!s])
		{
			s = (p->nodes[0] == node);
			if(p->nodes[s]->occupied && p->nodes[s]->occupied < next)
			{
				nextportal = p;
				nextnode = p->nodes[s];
				next = nextnode->occupied;
			}
		}
		node = nextnode;
		WindingCenter(nextportal->winding, mid);
		fprintf(linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
#if defined(USE_XML)
		point = xml_NodeForVec(mid);
		xmlAddChild(xml_node, point);
#endif
		count++;
	}
	// add the occupant center
	GetVectorForKey(node->occupant, "origin", mid);

	fprintf(linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
#if defined(USE_XML)
	point = xml_NodeForVec(mid);
	xmlAddChild(xml_node, point);
#endif
	Sys_FPrintf(SYS_VRB, "%9d point linefile\n", count + 1);

	fclose(linefile);

#if defined(USE_XML)
	return xml_node;
#endif
}
Ejemplo n.º 20
0
void SetupTraceNodes(void)
{
	/* note it */
	Sys_FPrintf(SYS_VRB, "--- SetupTraceNodes ---\n");

	/* find nodraw bit */
	noDrawContentFlags = noDrawSurfaceFlags = noDrawCompileFlags = 0;
	ApplySurfaceParm("nodraw", &noDrawContentFlags, &noDrawSurfaceFlags, &noDrawCompileFlags);

	/* create the baseline raytracing tree from the bsp tree */
	headNodeNum = SetupTraceNodes_r(0);

	/* create outside node for skybox surfaces */
	skyboxNodeNum = AllocTraceNode();

	/* populate the tree with triangles from the world and shadow casting entities */
	PopulateTraceNodes();

	/* create the raytracing bsp */
#if 1
	// Tr3B: this requires ridiculous much memory
	if(loMem == qfalse)
	{
		SubdivideTraceNode_r(headNodeNum, 0);
		SubdivideTraceNode_r(skyboxNodeNum, 0);
	}
#endif

	/* create triangles from the trace windings */
	TriangulateTraceNode_r(headNodeNum);
	TriangulateTraceNode_r(skyboxNodeNum);

	/* emit some stats */
	//% Sys_FPrintf( SYS_VRB, "%9d original triangles\n", numOriginalTriangles );
	Sys_FPrintf(SYS_VRB, "%9d trace windings (%.2fMB)\n", numTraceWindings,
				(float)(numTraceWindings * sizeof(*traceWindings)) / (1024.0f * 1024.0f));
	Sys_FPrintf(SYS_VRB, "%9d trace triangles (%.2fMB)\n", numTraceTriangles,
				(float)(numTraceTriangles * sizeof(*traceTriangles)) / (1024.0f * 1024.0f));
	Sys_FPrintf(SYS_VRB, "%9d trace nodes (%.2fMB)\n", numTraceNodes,
				(float)(numTraceNodes * sizeof(*traceNodes)) / (1024.0f * 1024.0f));
	Sys_FPrintf(SYS_VRB, "%9d leaf nodes (%.2fMB)\n", numTraceLeafNodes,
				(float)(numTraceLeafNodes * sizeof(*traceNodes)) / (1024.0f * 1024.0f));
	//% Sys_FPrintf( SYS_VRB, "%9d average triangles per leaf node\n", numTraceTriangles / numTraceLeafNodes );
	Sys_FPrintf(SYS_VRB, "%9d average windings per leaf node\n", numTraceWindings / (numTraceLeafNodes + 1));
	Sys_FPrintf(SYS_VRB, "%9d max trace depth\n", maxTraceDepth);

	/* free trace windings */
	free(traceWindings);
	numTraceWindings = 0;
	maxTraceWindings = 0;
	deadWinding = -1;

	/* debug code: write out trace triangles to an alias obj file */
#if 0
	{
		int             i, j;
		FILE           *file;
		char            filename[1024];
		traceWinding_t *tw;


		/* open the file */
		strcpy(filename, source);
		StripExtension(filename);
		strcat(filename, ".lin");
		Sys_Printf("Opening light trace file %s...\n", filename);
		file = fopen(filename, "w");
		if(file == NULL)
			Error("Error opening %s for writing", filename);

		/* walk node list */
		for(i = 0; i < numTraceWindings; i++)
		{
			tw = &traceWindings[i];
			for(j = 0; j < tw->numVerts + 1; j++)
				fprintf(file, "%f %f %f\n",
						tw->v[j % tw->numVerts].xyz[0], tw->v[j % tw->numVerts].xyz[1], tw->v[j % tw->numVerts].xyz[2]);
		}

		/* close it */
		fclose(file);
	}
#endif
}
Ejemplo n.º 21
0
void WINAPI Pointfile_Check( void ) {
    char name[1024];
    int size;
    char    *data;
    char  *text;
    int line = 1;
    vec3_t v;

    strcpy( name, currentmap );
    StripExtension( name );
    strcat( name, ".lin" );

    size = vfsLoadFullPathFile( name, (void**)&data );
    if ( size <= 0 ) {
        Sys_FPrintf( SYS_ERR, "Pointfile %s not found\n", name );
        return;
    }

    // store a pointer
    text = data;

    Sys_Printf( "Reading pointfile %s\n", name );

    g_pointfile.Init();

    while ( *data )
    {
        if ( sscanf( data,"%f %f %f", &v[0], &v[1], &v[2] ) != 3 ) {
            Sys_Printf( "Corrupt point file, line %d\n",line );
            break;
        }

        while ( *data && *data != '\n' )
        {
            if ( *( data - 1 ) == ' ' && *( data ) == '-' && *( data + 1 ) == ' ' ) {
                break;
            }
            data++;
        }
        // deal with zhlt style point files.
        if ( *data == '-' ) {
            if ( sscanf( data,"- %f %f %f", &v[0], &v[1], &v[2] ) != 3 ) {
                Sys_Printf( "Corrupt point file, line %d\n",line );
                break;
            }

            while ( *data && *data != '\n' )
                data++;

        }
        while ( *data == '\n' )
        {
            data++; // skip the \n
            line++;
        }
        g_pointfile.PushPoint( v );
    }

    g_free( text );

    g_pointfile.GenerateDisplayList();

    Sys_UpdateWindows( W_ALL );
}
Ejemplo n.º 22
0
/*
================
NumberLeafs_r
================
*/
void NumberLeafs_r (node_t *node, int c)
{
#if 0
	portal_t	*p;
#endif
	if ( node->planenum != PLANENUM_LEAF ) {
		// decision node
		node->cluster = -99;

		if(node->has_structural_children)
		{
#if 0
			if(c >= 0)
				Sys_FPrintf (SYS_ERR,"THIS CANNOT HAPPEN\n");
#endif
			NumberLeafs_r (node->children[0], c);
			NumberLeafs_r (node->children[1], c);
		}
		else
		{
			if(c < 0)
				c = num_visclusters++;
			NumberLeafs_r (node->children[0], c);
			NumberLeafs_r (node->children[1], c);
		}
		return;
	}
	
	node->area = -1;

	if ( node->opaque ) {
		// solid block, viewpoint never inside
		node->cluster = -1;
		return;
	}

	if(c < 0)
		c = num_visclusters++;
	
	node->cluster = c;

#if 0
	// count the portals
	for (p = node->portals ; p ; )
	{
		if (p->nodes[0] == node)		// only write out from first leaf
		{
			if (PortalPassable(p))
				num_visportals++;
			else
				num_solidfaces++;
			p = p->next[0];
		}
		else
		{
			if (!PortalPassable(p))
				num_solidfaces++;
			p = p->next[1];		
		}
	}
#endif
}
Ejemplo n.º 23
0
static void png_user_error_fn(png_structp png_ptr, png_const_charp error_message)
{
	Sys_FPrintf(SYS_ERR, "libpng error: %s\n", error_message);
	longjmp(png_ptr->jmpbuf, 0);
}
Ejemplo n.º 24
0
void Eclass_Init(){
	GSList *pFiles;

	// start by creating the default unknown eclass
	eclass_bad = EClass_Create( "UNKNOWN_CLASS", 0, 0.5, 0,NULL,NULL,NULL );

	// now scan the definitions
	_EClassTable *pTable = &g_EClassDefTable;
	while ( pTable )
	{
		// read in all scripts/*.<extension>
		pFiles = vfsGetFileList( "scripts", pTable->m_pfnGetExtension() );
		if ( pFiles ) {
			GSList *pFile = pFiles;
			while ( pFile )
			{
				/*!
				   \todo the MP/SP filtering rules need to be CLEANED UP and SANITIZED
				 */
				// HACK
				// JKII SP/MP mapping mode
				if ( g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game" ) {
					if ( !strcmp( ValueForKey( g_qeglobals.d_project_entity, "gamemode" ), "sp" ) ) {
						// SP mapping, ignore mp_*.def
						char *name = (char *)pFile->data;
						if ( name[0] == 'm' && name[1] == 'p' && name[2] == '_' ) {
							Sys_Printf( "Single Player mapping mode. Ignoring '%s'\n", name );
							pFile = pFile->next;
							continue;
						}
					}
					else
					{
						// MP mapping, ignore sp_*.def
						char *name = (char *)pFile->data;
						if ( name[0] == 's' && name[1] == 'p' && name[2] == '_' ) {
							Sys_Printf( "Multiplayer mapping mode. Ignoring '%s'\n", name );
							pFile = pFile->next;
							continue;
						}
					}
				}
				// RIANT
				// STVEF SP/MP mapping mode
				else if ( g_pGameDescription->mGameFile == "stvef.game" ) {
					if ( !strcmp( ValueForKey( g_qeglobals.d_project_entity, "gamemode" ), "sp" ) ) {
						// SP mapping, ignore mp_*.def
						char *name = (char *)pFile->data;
						if ( name[0] == 'm' && name[1] == 'p' && name[2] == '_' 
							|| name[0] == 'h' && name[1] == 'm' && name[2] == '_' ) {
							Sys_Printf( "Single Player mapping mode. Ignoring '%s'\n", name );
							pFile = pFile->next;
							continue;
						}
					}
					else
					{
						// HM mapping, ignore sp_*.def
						char *name = (char *)pFile->data;
						if ( name[0] == 's' && name[1] == 'p' && name[2] == '_' ) {
							Sys_Printf( "HoloMatch mapping mode. Ignoring '%s'\n", name );
							pFile = pFile->next;
							continue;
						}
					}
				}
				// for a given name, we grab the first .def in the vfs
				// this allows to override baseq3/scripts/entities.def for instance
				char relPath[PATH_MAX];
				strcpy( relPath, "scripts/" );
				strcat( relPath, (char*)pFile->data );
				char *fullpath = vfsGetFullPath( relPath, 0, 0 );
				if ( !fullpath ) {
					Sys_FPrintf( SYS_ERR, "Failed to find the full path for \"%s\" in the VFS\n", relPath );
				}
				else{
					pTable->m_pfnScanFile( fullpath );
				}
				if ( g_pGameDescription->mEClassSingleLoad ) {
					break;
				}
				pFile = pFile->next;
			}
			vfsClearFileDirList( &pFiles );
			pFiles = NULL;
		}
		else{
			Sys_FPrintf( SYS_ERR, "Didn't find any scripts/*.%s files to load EClass information\n", pTable->m_pfnGetExtension() );
		}

		// we deal with two formats max, if the other table exists, loop again
		if ( g_bHaveEClassExt && pTable == &g_EClassDefTable ) {
			pTable = &g_EClassExtTable;
		}
		else{
			pTable = NULL; // done, exit
		}
	}
	Eclass_CreateSpriteModelPaths();
}
Ejemplo n.º 25
0
void SetLightStyles( void )
{
	int			i, j, style, numStyles;
	qboolean	keepLights;
	const char	*t;
	entity_t	*e;
	epair_t		*ep, *next;
	char		value[ 10 ];
	char		lightTargets[ MAX_SWITCHED_LIGHTS ][ 64 ];
	int			lightStyles[ MAX_SWITCHED_LIGHTS ];
	
	
	/* ydnar: determine if we keep lights in the bsp */
	t = ValueForKey( &entities[ 0 ], "_keepLights" );
	keepLights = (t[ 0 ] == '1') ? qtrue : qfalse;
	
	/* any light that is controlled (has a targetname) must have a unique style number generated for it */
	numStyles = 0;
	for( i = 1; i < numEntities; i++ )
	{
		e = &entities[ i ];

		t = ValueForKey( e, "classname" );
		if( Q_strncasecmp( t, "light", 5 ) )
			continue;
		t = ValueForKey( e, "targetname" );
		if( t[ 0 ] == '\0' )
		{
			/* ydnar: strip the light from the BSP file */
			if( keepLights == qfalse )
			{
				ep = e->epairs;
				while( ep != NULL )
				{
					next = ep->next;
					free( ep->key );
					free( ep->value );
					free( ep );
					ep = next;
				}
				e->epairs = NULL;
				numStrippedLights++;
			}
			
			/* next light */
			continue;
		}
		
		/* get existing style */
		style = IntForKey( e, "style" );
		if( style < LS_NORMAL || style > LS_NONE )
			Error( "Invalid lightstyle (%d) on entity %d", style, i );
		
		/* find this targetname */
		for( j = 0; j < numStyles; j++ )
			if( lightStyles[ j ] == style && !strcmp( lightTargets[ j ], t ) )
				break;
		
		/* add a new style */
		if( j >= numStyles )
		{
			if( numStyles == MAX_SWITCHED_LIGHTS )
				Error( "MAX_SWITCHED_LIGHTS (%d) exceeded, reduce the number of lights with targetnames", MAX_SWITCHED_LIGHTS );
			strcpy( lightTargets[ j ], t );
			lightStyles[ j ] = style;
			numStyles++;
		}
		
		/* set explicit style */
		sprintf( value, "%d", 32 + j );
		SetKeyValue( e, "style", value );
		
		/* set old style */
		if( style != LS_NORMAL )
		{
			sprintf( value, "%d", style );
			SetKeyValue( e, "switch_style", value );
		}
	}
	
	/* emit some statistics */
	Sys_FPrintf( SYS_VRB, "%9d light entities stripped\n", numStrippedLights );
}
Ejemplo n.º 26
0
int ScaleBSPMain( int argc, char **argv )
{
	int			i;
	float		f, scale;
	vec3_t		vec;
	char		str[ 1024 ];
	
	
	/* arg checking */
	if( argc < 2 )
	{
		Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" );
		return 0;
	}
	
	/* get scale */
	scale = atof( argv[ argc - 2 ] );
	if( scale == 0.0f )
	{
		Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" );
		Sys_Printf( "Non-zero scale value required.\n" );
		return 0;
	}
	
	/* do some path mangling */
	strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
	StripExtension( source );
	DefaultExtension( source, ".bsp" );
	
	/* load the bsp */
	Sys_Printf( "Loading %s\n", source );
	LoadBSPFile( source );
	ParseEntities();
	
	/* note it */
	Sys_Printf( "--- ScaleBSP ---\n" );
	Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
	
	/* scale entity keys */
	for( i = 0; i < numBSPEntities && i < numEntities; i++ )
	{
		/* scale origin */
		GetVectorForKey( &entities[ i ], "origin", vec );
		if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) )
		{
			VectorScale( vec, scale, vec );
			sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
			SetKeyValue( &entities[ i ], "origin", str );
		}
		
		/* scale door lip */
		f = FloatForKey( &entities[ i ], "lip" );
		if( f )
		{
			f *= scale;
			sprintf( str, "%f", f );
			SetKeyValue( &entities[ i ], "lip", str );
		}
	}
	
	/* scale models */
	for( i = 0; i < numBSPModels; i++ )
	{
		VectorScale( bspModels[ i ].mins, scale, bspModels[ i ].mins );
		VectorScale( bspModels[ i ].maxs, scale, bspModels[ i ].maxs );
	}
	
	/* scale nodes */
	for( i = 0; i < numBSPNodes; i++ )
	{
		VectorScale( bspNodes[ i ].mins, scale, bspNodes[ i ].mins );
		VectorScale( bspNodes[ i ].maxs, scale, bspNodes[ i ].maxs );
	}
	
	/* scale leafs */
	for( i = 0; i < numBSPLeafs; i++ )
	{
		VectorScale( bspLeafs[ i ].mins, scale, bspLeafs[ i ].mins );
		VectorScale( bspLeafs[ i ].maxs, scale, bspLeafs[ i ].maxs );
	}
	
	/* scale drawverts */
	for( i = 0; i < numBSPDrawVerts; i++ )
		VectorScale( bspDrawVerts[ i ].xyz, scale, bspDrawVerts[ i ].xyz );
	
	/* scale planes */
	for( i = 0; i < numBSPPlanes; i++ )
		bspPlanes[ i ].dist *= scale;
	
	/* scale gridsize */
	GetVectorForKey( &entities[ 0 ], "gridsize", vec );
	if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) == 0.0f )
		VectorCopy( gridSize, vec );
	VectorScale( vec, scale, vec );
	sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
	SetKeyValue( &entities[ 0 ], "gridsize", str );
	
	/* write the bsp */
	UnparseEntities();
	StripExtension( source );
	DefaultExtension( source, "_s.bsp" );
	Sys_Printf( "Writing %s\n", source );
	WriteBSPFile( source );
	
	/* return to sender */
	return 0;
}
Ejemplo n.º 27
0
void Eclass_ScanFile( char *filename ){
	int size;
	char    *data;
	char temp[1024];
	GSList *l_classes = NULL;
	char token_debug[1024];  //++Hydra FIXME: cleanup this.
	bool done = false;
	int len,classtype;

	char *token = Token();

	QE_ConvertDOSToUnixName( temp, filename );

	size = vfsLoadFullPathFile( filename, (void**)&data );
	if ( size <= 0 ) {
		Sys_FPrintf( SYS_ERR, "Eclass_ScanFile: %s not found\n", filename );
		return;
	}
	Sys_Printf( "ScanFile: %s\n", temp );

	// start parsing the file
	StartTokenParsing( data );

	// build a list of base classes first

	while ( !done )
	{
		// find an @ sign.
		do
		{
			if ( !GetToken( true ) ) {
				done = true;
				break;
			}
		} while ( token[0] != '@' );

		strcpy( temp,token + 1 ); // skip the @

		classtype = CLASS_NOCLASS;
		if ( !stricmp( temp,"BaseClass" ) ) {
			classtype = CLASS_BASECLASS;
		}
		if ( !stricmp( temp,"PointClass" ) ) {
			classtype = CLASS_POINTCLASS;
		}
		if ( !stricmp( temp,"SolidClass" ) ) {
			classtype = CLASS_SOLIDCLASS;
		}

		if ( classtype ) {
			class_t *newclass = (class_t *) malloc( sizeof( class_s ) );
			memset( newclass, 0, sizeof( class_s ) );
			newclass->classtype = classtype;

			while ( 1 )
			{
				GetTokenExtra( false,"(",false ); // option or =
				strcpy( token_debug,token );

				if ( !strcmp( token,"=" ) ) {
					UnGetToken();
					break;
				}
				else
				{
					strlower( token );
					if ( !strcmp( token,"base" ) ) {
						GetTokenExtra( false,"(",true ); // (

						if ( !strcmp( token,"(" ) ) {
							while ( GetTokenExtra( false,",)",false ) ) // option) or option,
							{
								newclass->l_baselist = g_slist_append( newclass->l_baselist, strdup( token ) );

								GetTokenExtra( false,",)",true ); // , or )
								if ( !strcmp( token,")" ) ) {
									break;
								}

							}
						}
					}
					else if ( !strcmp( token,"size" ) ) {
						// parse (w h d) or (x y z, x y z)

						GetTokenExtra( false,"(",true ); // (
						if ( !strcmp( token,"(" ) ) {
							int sizedone = false;
							float w,h,d;
							GetToken( false );
							w = atof( token );
							GetToken( false );
							h = atof( token );
							GetToken( false ); // number) or number ,
							strcpy( temp,token );
							len = strlen( temp );
							if ( temp[len - 1] == ')' ) {
								sizedone = true;
							}
							temp[len - 1] = 0;
							d = atof( temp );
							if ( sizedone ) {
								// only one set of cordinates supplied, change the W,H,D to mins/maxs
								newclass->boundingbox[0][0] = 0 - ( w / 2 );
								newclass->boundingbox[1][0] = w / 2;
								newclass->boundingbox[0][1] = 0 - ( h / 2 );
								newclass->boundingbox[1][1] = h / 2;
								newclass->boundingbox[0][2] = 0 - ( d / 2 );
								newclass->boundingbox[1][2] = d / 2;
								newclass->gotsize = true;
							}
							else
							{
								newclass->boundingbox[0][0] = w;
								newclass->boundingbox[0][1] = h;
								newclass->boundingbox[0][2] = d;
								GetToken( false );
								newclass->boundingbox[1][0] = atof( token );
								GetToken( false );
								newclass->boundingbox[1][1] = atof( token );
/*
                GetToken(false); // "number)" or "number )"
                strcpy(temp,token);
                len = strlen(temp);
                if (temp[len-1] == ')')
                  temp[len-1] = 0;
                else
                  GetToken(false); // )
                newclass->boundingbox[1][2] = atof(temp);
 */
								GetTokenExtra( false,")",false ); // number
								newclass->boundingbox[1][2] = atof( token );
								newclass->gotsize = true;
								GetTokenExtra( false,")",true ); // )
							}
						}
					}
					else if ( !strcmp( token,"color" ) ) {
						GetTokenExtra( false,"(",true ); // (
						if ( !strcmp( token,"(" ) ) {
							// get the color values (0-255) and normalize them if required.
							GetToken( false );
							newclass->color[0] = atof( token );
							if ( newclass->color[0] > 1 ) {
								newclass->color[0] /= 255;
							}
							GetToken( false );
							newclass->color[1] = atof( token );
							if ( newclass->color[1] > 1 ) {
								newclass->color[1] /= 255;
							}
							GetToken( false );
							strcpy( temp,token );
							len = strlen( temp );
							if ( temp[len - 1] == ')' ) {
								temp[len - 1] = 0;
							}
							newclass->color[2] = atof( temp );
							if ( newclass->color[2] > 1 ) {
								newclass->color[2] /= 255;
							}
							newclass->gotcolor = true;
						}
					}
					else if ( !strcmp( token,"iconsprite" ) ) {
						GetTokenExtra( false,"(",true ); // (
						if ( !strcmp( token,"(" ) ) {
							GetTokenExtra( false,")",false ); // filename)
							// the model plugins will handle sprites too.
							// newclass->sprite = strdup(token);
							newclass->model = strdup( token );
							GetTokenExtra( false,")",true ); // )
						}
					}
					else if ( !strcmp( token,"model" ) ) {
						GetTokenExtra( false,"(",true ); // (
						if ( !strcmp( token,"(" ) ) {
							GetTokenExtra( false,")",false ); // filename)
							newclass->model = strdup( token );
							GetTokenExtra( false,")",true ); // )
						}
					}
					else
					{
						// Unsupported
						GetToken( false ); // skip it.
					}

				}
			}

			GetToken( false ); // =
			strcpy( token_debug,token );
			if ( !strcmp( token,"=" ) ) {
				GetToken( false );
				newclass->classname = strdup( token );
			}

			// Get the description
			if ( newclass->classtype != CLASS_BASECLASS ) {
				GetToken( false );
				if ( !strcmp( token,":" ) ) {
					GetToken( false );
					newclass->description = strdup( token );
				}
				else{ UnGetToken(); // no description
				}
			}

			// now build the option list.
			GetToken( true ); // [ or []

			if ( strcmp( token,"[]" ) ) { // got some options ?
				if ( !strcmp( token,"[" ) ) {
					// yup
					bool optioncomplete = false;
					option_t *newoption;

					while ( 1 )
					{
						GetToken( true );
						if ( !strcmp( token,"]" ) ) {
							break; // no more options

						}
						// parse the data and build the option_t

						strcpy( temp,token );
						len = strlen( temp );
						char *ptr = strchr( temp,'(' );

						if ( !ptr ) {
							break;
						}

						newoption = (option_t *) malloc( sizeof( option_s ) );
						memset( newoption, 0, sizeof( option_s ) );

						*ptr++ = 0;
						newoption->epairname = strdup( temp );

						len = strlen( ptr );
						if ( ptr[len - 1] != ')' ) {
							break;
						}

						ptr[len - 1] = 0;
						strlower( ptr );
						if ( !strcmp( ptr,"integer" ) ) {
							newoption->optiontype = OPTION_INTEGER;
						}
						else if ( !strcmp( ptr,"choices" ) ) {
							newoption->optiontype = OPTION_CHOICES;
						}
						else if ( !strcmp( ptr,"flags" ) ) {
							newoption->optiontype = OPTION_FLAGS;
						}
						else // string
						{
							newoption->optiontype = OPTION_STRING;
						}

						switch ( newoption->optiontype )
						{
						case OPTION_STRING:
						case OPTION_INTEGER:
							if ( !TokenAvailable() ) {
								optioncomplete = true;
								break;
							}
							GetToken( false ); // :
							strcpy( token_debug,token );
							if ( ( token[0] == ':' ) && ( strlen( token ) > 1 ) ) {
								newoption->optioninfo = strdup( token + 1 );
							}
							else
							{
								GetToken( false );
								newoption->optioninfo = strdup( token );
							}
							if ( TokenAvailable() ) { // default value ?
								GetToken( false );
								if ( !strcmp( token,":" ) ) {
									if ( GetToken( false ) ) {
										newoption->optiondefault = strdup( token );
										optioncomplete = true;
									}
								}
							}
							else
							{
								optioncomplete = true;
							}
							break;

						case OPTION_CHOICES:
							GetTokenExtra( false,":",true ); // : or :"something like this" (bah!)
							strcpy( token_debug,token );
							if ( ( token[0] == ':' ) && ( strlen( token ) > 1 ) ) {
								if ( token[1] == '\"' ) {
									strcpy( temp,token + 2 );
									while ( 1 )
									{
										if ( !GetToken( false ) ) {
											break;
										}
										strcat( temp," " );
										strcat( temp,token );
										len = strlen( temp );
										if ( temp[len - 1] == '\"' ) {
											temp[len - 1] = 0;
											break;
										}
									}
								}
								newoption->optioninfo = strdup( temp );
							}
							else
							{
								GetToken( false );
								newoption->optioninfo = strdup( token );
							}
							GetToken( false ); // : or =
							strcpy( token_debug,token );
							if ( !strcmp( token,":" ) ) {
								GetToken( false );
								newoption->optiondefault = strdup( token );
							}
							else
							{
								UnGetToken();
							}
						// And Follow on...
						case OPTION_FLAGS:
							GetToken( false ); // : or =
							strcpy( token_debug,token );
							if ( strcmp( token,"=" ) ) { // missing ?
								break;
							}

							GetToken( true ); // [
							strcpy( token_debug,token );
							if ( strcmp( token,"[" ) ) { // missing ?
								break;
							}

							choice_t *newchoice;
							while ( 1 )
							{
								GetTokenExtra( true,":",true ); // "]" or "number", or "number:"
								strcpy( token_debug,token );
								if ( !strcmp( token,"]" ) ) { // no more ?
									optioncomplete = true;
									break;
								}
								strcpy( temp,token );
								len = strlen( temp );
								if ( temp[len - 1] == ':' ) {
									temp[len - 1] = 0;
								}
								else
								{
									GetToken( false ); // :
									if ( strcmp( token,":" ) ) { // missing ?
										break;
									}
								}
								if ( !TokenAvailable() ) {
									break;
								}
								GetToken( false ); // the name

								newchoice = (choice_t *) malloc( sizeof( choice_s ) );
								memset( newchoice, 0, sizeof( choice_s ) );

								newchoice->value = atoi( temp );
								newchoice->name = strdup( token );

								newoption->choices = g_slist_append( newoption->choices, newchoice );

								// ignore any remaining tokens on the line
								while ( TokenAvailable() ) GetToken( false );

								// and it we found a "]" on the end of the line, put it back in the queue.
								if ( !strcmp( token,"]" ) ) {
									UnGetToken();
								}
							}
							break;

						}

						// add option to the newclass

						if ( optioncomplete ) {
							if ( newoption ) {
								// add it to the list.
								newclass->l_optionlist = g_slist_append( newclass->l_optionlist, newoption );
							}
						}
						else
						{
							Sys_Printf( "%WARNING: Parse error occured in '%s - %s'\n",classnames[newclass->classtype],newclass->classname );
							Free_Option( newoption );
						}

					}
				}
				else
				{
					UnGetToken(); // shouldn't get here.
				}
			}

			// add it to our list.
			l_classes = g_slist_append( l_classes, newclass );

		}
	}

	// finished with the file now.
	g_free( data );

	Sys_Printf( "FGD scan complete, building entities...\n" );

	// Once we get here we should have a few (!) lists in memory that we
	// can extract all the information required to build a the eclass_t structures.

	Create_EClasses( l_classes );

	// Free everything

	GSList *p = l_classes;
	while ( p )
	{
		class_t *tmpclass = (class_t *)p->data;

#ifdef FGD_VERBOSE
		// DEBUG: dump the info...
		Sys_Printf( "%s: %s (", classnames[tmpclass->classtype],tmpclass->classname );
		for ( GSList *tmp = tmpclass->l_baselist; tmp != NULL; tmp = tmp->next )
		{
			if ( tmp != tmpclass->l_baselist ) {
				Sys_Printf( ", " );
			}
			Sys_Printf( "%s", (char *)tmp->data );
		}
		if ( tmpclass->gotsize ) {
			sprintf( temp,"(%.0f %.0f %.0f) - (%.0f %.0f %.0f)",tmpclass->boundingbox[0][0],
					 tmpclass->boundingbox[0][1],
					 tmpclass->boundingbox[0][2],
					 tmpclass->boundingbox[1][0],
					 tmpclass->boundingbox[1][1],
					 tmpclass->boundingbox[1][2] );
		}
		else{ strcpy( temp,"No Size" ); }
		Sys_Printf( ") '%s' Size: %s",tmpclass->description ? tmpclass->description : "No description",temp );
		if ( tmpclass->gotcolor ) {
			sprintf( temp,"(%d %d %d)",tmpclass->color[0],
					 tmpclass->color[1],
					 tmpclass->color[2] );
		}
		else{ strcpy( temp,"No Color" ); }
		Sys_Printf( " Color: %s Options:\n",temp );
		if ( !tmpclass->l_optionlist ) {
			Sys_Printf( "  No Options\n" );
		}
		else
		{
			option_t *tmpoption;
			int count;
			GSList *olst;
			for ( olst = tmpclass->l_optionlist, count = 1; olst != NULL; olst = olst->next, count++ )
			{
				tmpoption = (option_t *)olst->data;
				Sys_Printf( "  %d, Type: %s, EPair: %s\n", count,optionnames[tmpoption->optiontype], tmpoption->epairname );

				choice_t *tmpchoice;
				GSList *clst;
				int ccount;
				for ( clst = tmpoption->choices, ccount = 1; clst != NULL; clst = clst->next, ccount++ )
				{
					tmpchoice = (choice_t *)clst->data;
					Sys_Printf( "    %d, Value: %d, Name: %s\n", ccount, tmpchoice->value, tmpchoice->name );
				}
			}
		}

#endif

		// free the baselist.
		ClearGSList( tmpclass->l_baselist );
		Free_Class( tmpclass );
		p = g_slist_remove( p, p->data );
	}

}
Ejemplo n.º 28
0
Archivo: fog.c Proyecto: otty/cake3
/*
=====================
FogDrawSurfs

Call after the surface list has been pruned, 
before tjunction fixing
before lightmap allocation
=====================
*/
void FogDrawSurfs(void)
{
	int             i, j, k;
	drawSurface_t  *ds;
	bspBrush_t     *b;
	vec3_t          mins, maxs;
	int             c_fogged;
	int             numBaseDrawSurfs;
	dfog_t         *fog;

	Sys_FPrintf(SYS_VRB, "----- FogDrawsurfs -----\n");

	c_fogged = 0;
	c_fogFragment = 0;

	// find all fog brushes
	for(b = entities[0].brushes; b; b = b->next)
	{
		if(!(b->contents & CONTENTS_FOG))
		{
			continue;
		}

		if(numFogs == MAX_MAP_FOGS)
		{
			Error("MAX_MAP_FOGS");
		}
		fog = &dfogs[numFogs];
		numFogs++;
		fog->brushNum = b->outputNumber;

		// find a side with a valid shaderInfo
		// non-axial fog columns may have bevel planes that need to be skipped
		for(i = 0; i < b->numsides; i++)
		{
			if(b->sides[i].shaderInfo && (b->sides[i].shaderInfo->contents & CONTENTS_FOG))
			{
				strcpy(fog->shader, b->sides[i].shaderInfo->shader);
				break;
			}
		}
		if(i == b->numsides)
		{
			continue;			// shouldn't happen
		}

		fog->visibleSide = -1;

		// clip each surface into this, but don't clip any of
		// the resulting fragments to the same brush
		numBaseDrawSurfs = numMapDrawSurfs;
		for(i = 0; i < numBaseDrawSurfs; i++)
		{
			ds = &mapDrawSurfs[i];

			// bound the drawsurf
			ClearBounds(mins, maxs);
			for(j = 0; j < ds->numVerts; j++)
			{
				AddPointToBounds(ds->verts[j].xyz, mins, maxs);
			}

			// check against the fog brush
			for(k = 0; k < 3; k++)
			{
				if(mins[k] > b->maxs[k])
				{
					break;
				}
				if(maxs[k] < b->mins[k])
				{
					break;
				}
			}
			if(k < 3)
			{
				continue;		// bboxes don't intersect
			}

			if(ds->mapBrush == b)
			{
				int             s;

				s = ds->side - b->sides;
				if(s <= 6)
				{				// not one of the reversed inside faces
					// this is a visible fog plane
					if(fog->visibleSide != -1)
					{
						Sys_Printf("WARNING: fog brush %i has multiple visible sides\n", b->brushnum);
					}
					fog->visibleSide = s;
				}
			}

			if(ds->miscModel)
			{
				// we could write splitting code for trimodels if we wanted to...
				c_fogged++;
				ds->fogNum = numFogs - 1;
			}
			else if(ds->patch)
			{
				if(ChopPatchByBrush(ds, b))
				{
					c_fogged++;
					ds->fogNum = numFogs - 1;
				}
			}
			else
			{
				if(ChopFaceByBrush(ds, b))
				{
					c_fogged++;
					ds->fogNum = numFogs - 1;
				}
			}
		}
	}

	// split the drawsurfs by the fog brushes

	Sys_FPrintf(SYS_VRB, "%5i fogs\n", numFogs);
	Sys_FPrintf(SYS_VRB, "%5i fog polygon fragments\n", c_fogFragment);
	Sys_FPrintf(SYS_VRB, "%5i fog patch fragments\n", c_fogPatchFragments);
	Sys_FPrintf(SYS_VRB, "%5i fogged drawsurfs\n", c_fogged);
}
Ejemplo n.º 29
0
static void png_user_warning_fn(png_structp png_ptr, png_const_charp warning_message)
{
	Sys_FPrintf(SYS_WRN, "libpng warning: %s\n", warning_message);
}
Ejemplo n.º 30
0
static void ProcessAdvertisements( void ) {
	int i;
	const char*         className;
	const char*         modelKey;
	int modelNum;
	bspModel_t*         adModel;
	bspDrawSurface_t*   adSurface;

	Sys_FPrintf( SYS_VRB, "--- ProcessAdvertisements ---\n" );

	for ( i = 0; i < numEntities; i++ ) {

		/* is an advertisement? */
		className = ValueForKey( &entities[ i ], "classname" );

		if ( !Q_stricmp( "advertisement", className ) ) {

			modelKey = ValueForKey( &entities[ i ], "model" );

			if ( strlen( modelKey ) > MAX_QPATH - 1 ) {
				Error( "Model Key for entity exceeds ad struct string length." );
			}
			else {
				if ( numBSPAds < MAX_MAP_ADVERTISEMENTS ) {
					bspAds[numBSPAds].cellId = IntForKey( &entities[ i ], "cellId" );
					strncpy( bspAds[numBSPAds].model, modelKey, sizeof( bspAds[numBSPAds].model ) );

					modelKey++;
					modelNum = atoi( modelKey );
					adModel = &bspModels[modelNum];

					if ( adModel->numBSPSurfaces != 1 ) {
						Error( "Ad cell id %d has more than one surface.", bspAds[numBSPAds].cellId );
					}

					adSurface = &bspDrawSurfaces[adModel->firstBSPSurface];

					// store the normal for use at run time.. all ad verts are assumed to
					// have identical normals (because they should be a simple rectangle)
					// so just use the first vert's normal
					VectorCopy( bspDrawVerts[adSurface->firstVert].normal, bspAds[numBSPAds].normal );

					// store the ad quad for quick use at run time
					if ( adSurface->surfaceType == MST_PATCH ) {
						int v0 = adSurface->firstVert + adSurface->patchHeight - 1;
						int v1 = adSurface->firstVert + adSurface->numVerts - 1;
						int v2 = adSurface->firstVert + adSurface->numVerts - adSurface->patchWidth;
						int v3 = adSurface->firstVert;
						VectorCopy( bspDrawVerts[v0].xyz, bspAds[numBSPAds].rect[0] );
						VectorCopy( bspDrawVerts[v1].xyz, bspAds[numBSPAds].rect[1] );
						VectorCopy( bspDrawVerts[v2].xyz, bspAds[numBSPAds].rect[2] );
						VectorCopy( bspDrawVerts[v3].xyz, bspAds[numBSPAds].rect[3] );
					}
					else {
						Error( "Ad cell %d has an unsupported Ad Surface type.", bspAds[numBSPAds].cellId );
					}

					numBSPAds++;
				}
				else {
					Error( "Maximum number of map advertisements exceeded." );
				}
			}
		}
	}

	Sys_FPrintf( SYS_VRB, "%9d in-game advertisements\n", numBSPAds );
}