Exemplo n.º 1
0
/**
 * @brief The incoming list will be freed before exiting
 */
tree_t *BuildTree (bspbrush_t *brushlist, const vec3_t mins, const vec3_t maxs)
{
	node_t *node;
	tree_t *tree;
	vec3_t blmins, blmaxs;

	Verb_Printf(VERB_EXTRA, "--- BrushBSP ---\n");

	tree = AllocTree();

	ClearBounds(blmins, blmaxs);
	BrushlistCalcStats(brushlist, blmins, blmaxs);
	tree->aabb.add(blmins);
	tree->aabb.add(blmaxs);

	c_nodes = 0;
	c_nonvis = 0;
	node = AllocNode();

	node->volume = BrushFromBounds(mins, maxs);

	tree->headnode = node;

	node = BuildTree_r(node, brushlist);

	Verb_Printf(VERB_EXTRA, "%5i visible nodes\n", c_nodes / 2 - c_nonvis);
	Verb_Printf(VERB_EXTRA, "%5i nonvis nodes\n", c_nonvis);
	Verb_Printf(VERB_EXTRA, "%5i leafs\n", (c_nodes + 1) / 2);
	return tree;
}
Exemplo n.º 2
0
/**
 * @sa PruneNodes_r
 */
void PruneNodes (node_t *node)
{
	Verb_Printf(VERB_EXTRA, "--- PruneNodes ---\n");
	c_pruned = 0;
	PruneNodes_r(node);
	Verb_Printf(VERB_EXTRA, "%5i pruned nodes\n", c_pruned);
}
Exemplo n.º 3
0
void SplitBrushList (bspbrush_t* brushes, uint16_t planenum, bspbrush_t** front, bspbrush_t** back)
{
	bspbrush_t* brush;

	*front = *back = nullptr;

	for (brush = brushes; brush; brush = brush->next) {
		const int sides = brush->side;
		bspbrush_t* newbrush;

		if (sides == PSIDE_BOTH) {	/* split into two brushes */
			bspbrush_t* newbrush2;
			SplitBrush(brush, planenum, &newbrush, &newbrush2);
			if (newbrush) {
				newbrush->next = *front;
				Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to front list.\n", newbrush->original->brushnum);
				*front = newbrush;
			}
			if (newbrush2) {
				newbrush2->next = *back;
				Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to back list.\n", newbrush2->original->brushnum);
				*back = newbrush2;
			}
			continue;
		}

		newbrush = CopyBrush(brush);

		/* if the planenum is actually a part of the brush
		 * find the plane and flag it as used so it won't be tried
		 * as a splitter again */
		if (sides & PSIDE_FACING) {
			int i;
			for (i = 0; i < newbrush->numsides; i++) {
				side_t* side = newbrush->sides + i;
				if ((side->planenum & ~1) == planenum)
					side->texinfo = TEXINFO_NODE;
			}
		}

		if (sides & PSIDE_FRONT) {
			newbrush->next = *front;
			*front = newbrush;
			Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to front list.\n", newbrush->original->brushnum);
			continue;
		}
		if (sides & PSIDE_BACK) {
			newbrush->next = *back;
			Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to back list.\n", newbrush->original->brushnum);
			*back = newbrush;
			continue;
		}
		Verb_Printf(VERB_DUMP, "SplitBrushList: Brush %i fell off the map.\n", newbrush->original->brushnum);
	}
}
Exemplo n.º 4
0
/**
 * @sa LoadMapFile
 * @sa FixErrors
 */
void WriteMapFile (const char* filename)
{
	int removed;

	Verb_Printf(VERB_NORMAL, "writing map: '%s'\n", filename);

	ScopedFile f;
	FS_OpenFile(filename, &f, FILE_WRITE);
	if (!f)
		Sys_Error("Could not open %s for writing", filename);

	removed = 0;
	FS_Printf(&f, "\n");
	for (int i = 0; i < num_entities; i++) {
		const entity_t* mapent = &entities[i];
		const epair_t* e = mapent->epairs;

		/* maybe we don't want to write it back into the file */
		if (mapent->skip) {
			removed++;
			continue;
		}
		FS_Printf(&f, "// entity %i\n{\n", i - removed);
		WriteMapEntities(&f, e);

		/* need 2 counters. j counts the brushes in the source entity.
		 * jc counts the brushes written back. they may differ if some are skipped,
		 * eg they are microbrushes */
		int j, jc;
		for (j = 0, jc = 0; j < mapent->numbrushes; j++) {
			const mapbrush_t* brush = &mapbrushes[mapent->firstbrush + j];
			if (brush->skipWriteBack)
				continue;
			WriteMapBrush(brush, jc++, &f);
		}

		/* add brushes from func_groups with single members to worldspawn */
		if (i == 0) {
			int numToAdd;
			mapbrush_t** brushesToAdd = Check_ExtraBrushesForWorldspawn(&numToAdd);
			if (brushesToAdd != nullptr) {
				for (int k = 0; k < numToAdd; k++) {
					if (brushesToAdd[k]->skipWriteBack)
						continue;
					WriteMapBrush(brushesToAdd[k], j++, &f);
				}
				Mem_Free(brushesToAdd);
			}
		}
		FS_Printf(&f, "}\n");
	}

	if (removed)
		Verb_Printf(VERB_NORMAL, "removed %i entities\n", removed);
}
Exemplo n.º 5
0
/**
 * @brief Writes the draw nodes
 * @note Called after a drawing hull is completed
 */
static int EmitDrawNode_r (node_t* node)
{
	const char* side[2] = {"front", "back"};
	dBspNode_t* n;
	const face_t* f;
	int i;

	if (node->planenum == PLANENUM_LEAF) {
		Verb_Printf(VERB_DUMP, "EmitDrawNode_r: creating singleton leaf.\n");
		EmitLeaf(node);
		return -curTile->numleafs;
	}

	/* emit a node	 */
	if (curTile->numnodes >= MAX_MAP_NODES)
		Sys_Error("MAX_MAP_NODES (%i)", curTile->numnodes);
	n = &curTile->nodes[curTile->numnodes];
	Verb_Printf(VERB_DUMP, "EmitDrawNode_r: creating bsp node %i\n", curTile->numnodes);
	curTile->numnodes++;

	VectorCopy(node->mins, n->mins);
	VectorCopy(node->maxs, n->maxs);

	if (node->planenum & 1)
		Sys_Error("EmitDrawNode_r: odd planenum: %i", node->planenum);
	n->planenum = node->planenum;
	n->firstface = curTile->numfaces;

	if (!node->faces)
		c_nofaces++;
	else
		c_facenodes++;

	for (f = node->faces; f; f = f->next)
		EmitFace(f);

	n->numfaces = curTile->numfaces - n->firstface;

	/* recursively output the other nodes */
	for (i = 0; i < 2; i++) {
		if (node->children[i]->planenum == PLANENUM_LEAF) {
			Verb_Printf(VERB_DUMP, "EmitDrawNode_r: creating child leaf for %s of bsp node " UFO_SIZE_T ".\n", side[i], n - curTile->nodes);
			n->children[i] = -(curTile->numleafs + 1);
			EmitLeaf(node->children[i]);
		} else {
			Verb_Printf(VERB_DUMP, "EmitDrawNode_r: adding child node for bsp node " UFO_SIZE_T ".\n", n - curTile->nodes);
			n->children[i] = curTile->numnodes;
			EmitDrawNode_r(node->children[i]);
		}
	}

	return n - curTile->nodes;
}
Exemplo n.º 6
0
/**
 * @brief Calculates the texture color that is used for light emitting surfaces
 */
void CalcTextureReflectivity (void)
{
	int i, j, texels = 0;
	char path[MAX_QPATH];
	int color[3];
	SDL_Surface* surf;

	/* always set index 0 even if no textures */
	VectorSet(texture_reflectivity[0], 0.5, 0.5, 0.5);

	VectorSet(color, 0, 0, 0);

	for (i = 0; i < curTile->numtexinfo; i++) {
		/* see if an earlier texinfo already got the value */
		for (j = 0; j < i; j++) {
			if (Q_streq(curTile->texinfo[i].texture, curTile->texinfo[j].texture)) {
				VectorCopy(texture_reflectivity[j], texture_reflectivity[i]);
				break;
			}
		}
		if (j != i) /* earlier texinfo found, continue */
			continue;

		/* load the image file */
		Com_sprintf(path, sizeof(path), "textures/%s", curTile->texinfo[i].texture);
		if (!(surf = Img_LoadImage(path))) {
			Verb_Printf(VERB_NORMAL, "Couldn't load %s\n", path);
			VectorSet(texture_reflectivity[i], 0.5, 0.5, 0.5);
			continue;
		}

		/* calculate average color */
		texels = surf->w * surf->h;
		color[0] = color[1] = color[2] = 0;

		for(j = 0; j < texels; j++){
			const byte* pos = (byte*)surf->pixels + j * 4;
			color[0] += *pos++; /* r */
			color[1] += *pos++; /* g */
			color[2] += *pos++; /* b */
		}

		Verb_Printf(VERB_EXTRA, "Loaded %s (%dx%d)\n", curTile->texinfo[i].texture, surf->w, surf->h);

		SDL_FreeSurface(surf);

		for(j = 0; j < 3; j++){
			const float r = color[j] / texels / 255.0;
			texture_reflectivity[i][j] = r;
		}
	}
}
Exemplo n.º 7
0
void MakeFaces (node_t* node)
{
	Verb_Printf(VERB_EXTRA, "--- MakeFaces ---\n");
	c_merge = 0;
	c_subdivide = 0;
	c_nodefaces = 0;

	MakeFaces_r(node);

	Verb_Printf(VERB_EXTRA, "%5i makefaces\n", c_nodefaces);
	Verb_Printf(VERB_EXTRA, "%5i merged\n", c_merge);
	Verb_Printf(VERB_EXTRA, "%5i subdivided\n", c_subdivide);
}
Exemplo n.º 8
0
/**
 * @brief Entry point for all thread work requests.
 */
void RunThreadsOn (void (*func)(unsigned int), int unsigned workcount, qboolean progress, const char *id)
{
	int start, end;

	if (threadstate.numthreads < 1)  /* ensure safe thread counts */
		threadstate.numthreads = 1;

	if (threadstate.numthreads > MAX_THREADS)
		threadstate.numthreads = MAX_THREADS;

	threadstate.workindex = 0;
	threadstate.workcount = workcount;
	threadstate.workfrac = -1;
	threadstate.progress = progress;
	threadstate.worktick = sqrt(workcount) + 1;

	WorkFunction = func;

	start = time(NULL);

	if (threadstate.progress) {
		fprintf(stdout, "%10s: ", id);
		fflush(stdout);
	}

	RunThreads();

	end = time(NULL);

	if (threadstate.progress) {
		Verb_Printf(VERB_NORMAL, " (time: %6is, #: %i)\n", end - start, workcount);
	}
}
Exemplo n.º 9
0
/**
 * @brief makes basewindigs for sides and mins/maxs for the brush
 * @returns false if the brush doesn't enclose a valid volume
 */
static void CreateBrushWindings (bspbrush_t* brush)
{
	int i;

	for (i = 0; i < brush->numsides; i++) {
		side_t* side = &brush->sides[i];
		const plane_t* plane = &mapplanes[side->planenum];
		int j;

		/* evidence that winding_t represents a hessian normal plane */
		winding_t* w = BaseWindingForPlane(plane->normal, plane->dist);

		for (j = 0; j < brush->numsides && w; j++) {
			if (i == j)
				continue;
			/* back side clipaway */
			if (brush->sides[j].planenum == (side->planenum ^ 1))
				continue;
			if (brush->sides[j].bevel)
				continue;
			plane = &mapplanes[brush->sides[j].planenum ^ 1];
			ChopWindingInPlace(&w, plane->normal, plane->dist, 0); /*CLIP_EPSILON); */

			/* fix broken windings that would generate trifans */
			if (!FixWinding(w))
				Verb_Printf(VERB_EXTRA, "removed degenerated edge(s) from winding\n");
		}

		side->winding = w;
	}

	BoundBrush(brush);
}
Exemplo n.º 10
0
static node_t *BuildTree_r (node_t *node, bspbrush_t *brushes)
{
	node_t *newnode;
	side_t *bestside;
	int i;
	bspbrush_t *children[2];

	if (threadstate.numthreads == 1)
		c_nodes++;

	/* find the best plane to use as a splitter */
	bestside = SelectSplitSide(brushes, node->volume);
	if (!bestside) {
		/* leaf node */
		LeafNode(node, brushes);
		Verb_Printf(VERB_DUMP, "BuildTree_r: Created a leaf node.\n");
		return node;
	}
	/* make sure the selected plane hasn't been used before. */
	CheckPlaneAgainstParents(bestside->planenum, node);

	Verb_Printf(VERB_DUMP, "BuildTree_r: splitting along plane %i\n", (int)bestside->planenum);

	/* this is a splitplane node */
	node->side = bestside;
	node->planenum = bestside->planenum & ~1;	/* always use front facing */

	SplitBrushList(brushes, node->planenum, &children[0], &children[1]);
	FreeBrushList(brushes);

	/* allocate children before recursing */
	for (i = 0; i < 2; i++) {
		newnode = AllocNode();
		newnode->parent = node;
		node->children[i] = newnode;
	}

	SplitBrush(node->volume, node->planenum, &node->children[0]->volume,
		&node->children[1]->volume);

	/* recursively process children */
	for (i = 0; i < 2; i++) {
		node->children[i] = BuildTree_r(node->children[i], children[i]);
	}

	return node;
}
Exemplo n.º 11
0
/**
 * @brief Finds a brush side to use for texturing the given portal
 */
static void FindPortalSide (portal_t *p)
{
	uint32_t viscontents;
	bspbrush_t *bb;
	int i, j, planenum;
	side_t *bestside;
	float bestdot;

	/* decide which content change is strongest
	 * solid > water, etc */
	viscontents = VisibleContents(p->nodes[0]->contentFlags ^ p->nodes[1]->contentFlags);
	if (!viscontents)
		return;

	planenum = p->onnode->planenum;
	bestside = NULL;
	bestdot = 0;

	for (j = 0; j < 2; j++) {
		const node_t *n = p->nodes[j];
		const plane_t *p1 = &mapplanes[p->onnode->planenum];
		for (bb = n->brushlist; bb; bb = bb->next) {
			const mapbrush_t *brush = bb->original;

			if (!(brush->contentFlags & viscontents))
				continue;
			for (i = 0; i < brush->numsides; i++) {
				side_t *side = &brush->original_sides[i];
				float dot;
				const plane_t *p2;

				if (side->bevel)
					continue;
				/* non-visible */
				if (side->texinfo == TEXINFO_NODE)
					continue;
				/* exact match */
				if ((side->planenum &~ 1) == planenum) {
					bestside = &brush->original_sides[i];
					goto gotit;
				}
				/* see how close the match is */
				p2 = &mapplanes[side->planenum &~ 1];
				dot = DotProduct(p1->normal, p2->normal);
				if (dot > bestdot) {
					bestdot = dot;
					bestside = side;
				}
			}
		}
	}

gotit:
	if (!bestside)
		Verb_Printf(VERB_EXTRA, "WARNING: side not found for portal\n");

	p->sidefound = qtrue;
	p->side = bestside;
}
Exemplo n.º 12
0
/**
 * @brief copies working data for a bsp tree into the structures used to create the bsp file.
 * @param[in] headnode the top-most node in this bsp tree
 * @return the index to the head node created.
 */
int WriteBSP (node_t* headnode)
{
	int oldfaces, emittedHeadnode;

	c_nofaces = 0;
	c_facenodes = 0;

	Verb_Printf(VERB_EXTRA, "--- WriteBSP ---\n");

	oldfaces = curTile->numfaces;
	emittedHeadnode = EmitDrawNode_r(headnode);

	Verb_Printf(VERB_EXTRA, "%5i nodes with faces\n", c_facenodes);
	Verb_Printf(VERB_EXTRA, "%5i nodes without faces\n", c_nofaces);
	Verb_Printf(VERB_EXTRA, "%5i faces\n", curTile->numfaces - oldfaces);

	return emittedHeadnode;
}
Exemplo n.º 13
0
/**
 * @param[in] n The node nums
 * @sa R_ModLoadNodes
 */
static int32_t BuildNodeChildren (const int n[3])
{
	int32_t node = LEAFNODE;
	int i;

	for (i = 0; i < 3; i++) {
		dBspNode_t *newnode;
		vec3_t newmins, newmaxs, addvec;

		if (n[i] == LEAFNODE)
			continue;

		if (node == LEAFNODE) {
			/* store the valid node */
			node = n[i];

			ClearBounds(newmins, newmaxs);
			VectorCopy(curTile->nodes[node].mins, addvec);
			AddPointToBounds(addvec, newmins, newmaxs);
			VectorCopy(curTile->nodes[node].maxs, addvec);
			AddPointToBounds(addvec, newmins, newmaxs);
		} else {
			/* add a new "special" dnode and store it */
			newnode = &curTile->nodes[curTile->numnodes];
			curTile->numnodes++;

			newnode->planenum = PLANENUM_LEAF;
			newnode->children[0] = node;
			newnode->children[1] = n[i];
			newnode->firstface = 0;
			newnode->numfaces = 0;

			ClearBounds(newmins, newmaxs);
			VectorCopy(curTile->nodes[node].mins, addvec);
			AddPointToBounds(addvec, newmins, newmaxs);
			VectorCopy(curTile->nodes[node].maxs, addvec);
			AddPointToBounds(addvec, newmins, newmaxs);
			VectorCopy(curTile->nodes[n[i]].mins, addvec);
			AddPointToBounds(addvec, newmins, newmaxs);
			VectorCopy(curTile->nodes[n[i]].maxs, addvec);
			AddPointToBounds(addvec, newmins, newmaxs);
			VectorCopy(newmins, newnode->mins);
			VectorCopy(newmaxs, newnode->maxs);

			node = curTile->numnodes - 1;
		}

		AddPointToBounds(newmins, worldMins, worldMaxs);
		AddPointToBounds(newmaxs, worldMins, worldMaxs);

		Verb_Printf(VERB_DUMP, "BuildNodeChildren: node=%i (%i %i %i) (%i %i %i)\n", node,
			curTile->nodes[node].mins[0], curTile->nodes[node].mins[1], curTile->nodes[node].mins[2], curTile->nodes[node].maxs[0], curTile->nodes[node].maxs[1], curTile->nodes[node].maxs[2]);
	}

	/* return the last stored node */
	return node;
}
Exemplo n.º 14
0
static void LeafNode (node_t *node, bspbrush_t *brushes)
{
	node->side = nullptr;
	node->planenum = PLANENUM_LEAF;

	Verb_Printf(VERB_DUMP, "LeafNode: scanning brushes.\n");

	node->contentFlags = BrushListCalcContents(brushes);
	node->brushlist = brushes;
}
Exemplo n.º 15
0
/**
 * @brief Finishes a new bsp and writes to disk
 * @sa BeginBSPFile
 */
void EndBSPFile (const char* filename)
{
	EmitBrushes();
	EmitPlanes();
	UnparseEntities();

	/* write the map */
	Verb_Printf(VERB_LESS, "Writing %s\n", filename);
	WriteBSPFile(filename);
}
Exemplo n.º 16
0
/**
 * @brief Counts the faces and calculate the aabb
 */
void BrushlistCalcStats (bspbrush_t* brushlist, vec3_t mins, vec3_t maxs)
{
	bspbrush_t* b;
	int c_faces = 0, c_nonvisfaces = 0, c_brushes = 0;

	for (b = brushlist; b; b = b->next) {
		int i;
		vec_t volume;

		c_brushes++;

		volume = BrushVolume(b);
		if (volume < config.microvolume) {
			Com_Printf("\nWARNING: entity %i, brush %i: microbrush, volume %.3g\n",
				b->original->entitynum, b->original->brushnum, volume);
		}

		for (i = 0; i < b->numsides; i++) {
			side_t* side = &b->sides[i];
			if (side->bevel)
				continue;
			if (!side->winding)
				continue;
			if (side->texinfo == TEXINFO_NODE)
				continue;
			if (side->visible)
				c_faces++;
			else
				c_nonvisfaces++;
		}

		AddPointToBounds(b->mins, mins, maxs);
		AddPointToBounds(b->maxs, mins, maxs);
	}

	Verb_Printf(VERB_EXTRA, "%5i brushes\n", c_brushes);
	Verb_Printf(VERB_EXTRA, "%5i visible faces\n", c_faces);
	Verb_Printf(VERB_EXTRA, "%5i nonvisible faces\n", c_nonvisfaces);
}
Exemplo n.º 17
0
/**
 * @brief Get the content flags for a given brush
 * @param b The mapbrush to get the content flags for
 * @return The calculated content flags
 */
static int BrushContents (mapbrush_t* b)
{
	int contentFlags, i;
	const side_t* s;

	s = &b->original_sides[0];
	contentFlags = s->contentFlags;
	for (i = 1; i < b->numsides; i++, s++) {
		if (s->contentFlags != contentFlags) {
			Verb_Printf(VERB_EXTRA, "Entity %i, Brush %i: mixed face contents (f: %i, %i)\n"
				, b->entitynum, b->brushnum, s->contentFlags, contentFlags);
			break;
		}
	}

	return contentFlags;
}
Exemplo n.º 18
0
void MarkVisibleSides (tree_t *tree, int startbrush, int endbrush)
{
	int i;

	Verb_Printf(VERB_EXTRA, "--- MarkVisibleSides ---\n");

	/* clear all the visible flags */
	for (i = startbrush; i < endbrush; i++) {
		mapbrush_t *mb = &mapbrushes[i];
		const int numsides = mb->numsides;
		int j;

		for (j = 0; j < numsides; j++)
			mb->original_sides[j].visible = qfalse;
	}

	/* set visible flags on the sides that are used by portals */
	MarkVisibleSides_r(tree->headnode);
}
Exemplo n.º 19
0
/**
 * @sa ProcessSubModel
 * @sa ConstructLevelNodes_r
 */
void FixTjuncs (node_t* headnode)
{
	/* snap and merge all vertexes */
	Verb_Printf(VERB_EXTRA, "---- snap verts ----\n");
	OBJZERO(hashverts);
	c_totalverts = 0;
	c_uniqueverts = 0;
	c_faceoverflows = 0;
	EmitVertexes_r(headnode);
	Verb_Printf(VERB_EXTRA, "%i unique from %i\n", c_uniqueverts, c_totalverts);

	/* break edges on tjunctions */
	Verb_Printf(VERB_EXTRA, "---- tjunc ----\n");
	c_degenerate = 0;
	c_facecollapse = 0;
	c_tjunctions = 0;
	if (!config.notjunc)
		FixEdges_r(headnode);
	Verb_Printf(VERB_EXTRA, "%5i edges degenerated\n", c_degenerate);
	Verb_Printf(VERB_EXTRA, "%5i faces degenerated\n", c_facecollapse);
	Verb_Printf(VERB_EXTRA, "%5i edges added by tjunctions\n", c_tjunctions);
	Verb_Printf(VERB_EXTRA, "%5i faces added by tjunctions\n", c_faceoverflows);
	Verb_Printf(VERB_EXTRA, "%5i bad start verts\n", c_badstartverts);
}
Exemplo n.º 20
0
/**
 * @brief Emits a leafnode to the bsp file
 */
static void EmitLeaf (const node_t* node)
{
	dBspLeaf_t* leaf_p;
	int i;
	const bspbrush_t* b;

	/* emit a leaf */
	if (curTile->numleafs >= MAX_MAP_LEAFS)
		Sys_Error("MAX_MAP_LEAFS (%i)", curTile->numleafs);

	leaf_p = &curTile->leafs[curTile->numleafs];
	curTile->numleafs++;

	leaf_p->contentFlags = node->contentFlags;
	leaf_p->area = node->area;

	/* write bounding box info */
	VectorCopy(node->mins, leaf_p->mins);
	VectorCopy(node->maxs, leaf_p->maxs);

	/* write the leafbrushes */
	leaf_p->firstleafbrush = curTile->numleafbrushes;
	for (b = node->brushlist; b; b = b->next) {
		if (curTile->numleafbrushes >= MAX_MAP_LEAFBRUSHES)
			Sys_Error("MAX_MAP_LEAFBRUSHES (%i)", curTile->numleafbrushes);

		int brushnum = b->original - mapbrushes;
		for (i = leaf_p->firstleafbrush; i < curTile->numleafbrushes; i++)
			if (curTile->leafbrushes[i] == brushnum)
				break;
		if (i == curTile->numleafbrushes) {
			Verb_Printf(VERB_DUMP, "EmitLeaf: adding brush %i to leaf %i\n", brushnum, curTile->numleafs - 1);
			curTile->leafbrushes[curTile->numleafbrushes] = brushnum;
			curTile->numleafbrushes++;
		}
	}
	leaf_p->numleafbrushes = curTile->numleafbrushes - leaf_p->firstleafbrush;
}
Exemplo n.º 21
0
/**
 * @sa DoRouting
 */
static void CheckConnectionsThread (unsigned int unitnum)
{
	/* get coordinates of that unit */
	const int numDirs = CORE_DIRECTIONS / (1 + RT_IS_BIDIRECTIONAL);
	const int dir = (unitnum % numDirs) * (RT_IS_BIDIRECTIONAL ? 2 : 1);
	const int y = (unitnum / numDirs) % PATHFINDING_WIDTH;
	const int x = (unitnum / numDirs / PATHFINDING_WIDTH) % PATHFINDING_WIDTH;
	const int actorSize = unitnum / numDirs / PATHFINDING_WIDTH / PATHFINDING_WIDTH;

	/* test bounds - the size adjustment is needed because large actor cells occupy multiple cell units. */
	if (x > wpMaxs[0] - actorSize || y > wpMaxs[1] - actorSize
	 || x < wpMins[0] || y < wpMins[1] ) {
		/* don't enter - outside world */
		/* Com_Printf("x%i y%i z%i dir%i size%i (%i, %i, %i) (%i, %i, %i)\n", x, y, z, dir, size, wpMins[0], wpMins[1], wpMins[2], wpMaxs[0], wpMaxs[1], wpMaxs[2]); */
		return;
	}

	Verb_Printf(VERB_EXTRA, "%i %i %i %i (%i, %i, %i) (%i, %i, %i)\n", x, y, dir, actorSize, wpMins[0], wpMins[1], wpMins[2], wpMaxs[0], wpMaxs[1], wpMaxs[2]);

	RT_UpdateConnectionColumn(&mapTiles, Nmap, actorSize + 1, x, y, dir);

	/* Com_Printf("z:%i nz:%i\n", z, new_z); */
}
Exemplo n.º 22
0
/**
 * @sa ProcessWorldModel
 * @sa ProcessSubModel
 */
void ProcessModels (const char* filename)
{
    int entity_num;

    BeginBSPFile();

    for (entity_num = 0; entity_num < num_entities; entity_num++) {
        if (!entities[entity_num].numbrushes)
            continue;

        Verb_Printf(VERB_EXTRA, "############### model %i ###############\n", curTile->nummodels);

        if (entity_num == 0)
            ProcessWorldModel(entity_num);
        else
            ProcessSubModel(entity_num);

        if (!config.verboseentities)
            config.verbose = false;	/* don't bother printing submodels */
    }

    EndBSPFile(filename);
}
Exemplo n.º 23
0
/**
 * @brief process brushes with that level mask
 * @param[in] levelnum is the level mask
 * @note levelnum
 * 256: weaponclip-level
 * 257: actorclip-level
 * 258: stepon-level
 * 259: tracing structure
 * @sa ProcessWorldModel
 * @sa ConstructLevelNodes_r
 */
void ProcessLevel (unsigned int levelnum)
{
	vec3_t mins, maxs;
	dBspModel_t *dm;

	/* oversizing the blocks guarantees that all the boundaries will also get nodes. */
	/* get maxs */
	mins[0] = (config.block_xl) * 512.0 + 1.0;
	mins[1] = (config.block_yl) * 512.0 + 1.0;
	mins[2] = -MAX_WORLD_WIDTH + 1.0;

	maxs[0] = (config.block_xh + 1.0) * 512.0 - 1.0;
	maxs[1] = (config.block_yh + 1.0) * 512.0 - 1.0f;
	maxs[2] = MAX_WORLD_WIDTH - 1.0;

	Verb_Printf(VERB_EXTRA, "Process levelnum %i (curTile->nummodels: %i)\n", levelnum, curTile->nummodels);
	/* Com_Printf("Process levelnum %i (curTile->nummodels: %i)\n", levelnum, curTile->nummodels); */

	/** @note Should be reentrant as each thread has a unique levelnum at any given time */
	dm = &curTile->models[levelnum];
	OBJZERO(*dm);

	/** @todo Check what happens if two threads do the memcpy */
	/* back copy backup brush sides structure */
	/* to reset all the changed values (especialy "finished") */
	memcpy(mapbrushes, mapbrushes + nummapbrushes, sizeof(mapbrush_t) * nummapbrushes);

	/* Store face number for later use */
	dm->firstface = curTile->numfaces;
	dm->headnode = ConstructLevelNodes_r(levelnum, mins, maxs, entityNum);
	/* This here replaces the calls to EndModel */
	dm->numfaces = curTile->numfaces - dm->firstface;

/*	if (!dm->numfaces)
		Com_Printf("level: %i -> %i : f %i\n", levelnum, dm->headnode, dm->numfaces);
*/
}
Exemplo n.º 24
0
/**
 * @brief print map stats on -stats
 */
void Check_Stats(void) {
	vec3_t worldSize;
	int j;
	int* entNums;

	Check_InitEntityDefs();

	entNums = Mem_AllocTypeN(int, numEntityDefs);

	Check_MapSize(worldSize);
	Verb_Printf(VERB_NORMAL, "        Number of brushes: %i\n",nummapbrushes);
	Verb_Printf(VERB_NORMAL, "         Number of planes: %i\n",nummapplanes);
	Verb_Printf(VERB_NORMAL, "    Number of brush sides: %i\n",nummapbrushsides);
	Verb_Printf(VERB_NORMAL, "         Map size (units): %.0f %.0f %.0f\n", worldSize[0], worldSize[1], worldSize[2]);
	Verb_Printf(VERB_NORMAL, "        Map size (fields): %.0f %.0f %.0f\n", worldSize[0] / UNIT_SIZE, worldSize[1] / UNIT_SIZE, worldSize[2] / UNIT_HEIGHT);
	Verb_Printf(VERB_NORMAL, "         Map size (tiles): %.0f %.0f %.0f\n", worldSize[0] / (MIN_TILE_SIZE), worldSize[1] / (MIN_TILE_SIZE), worldSize[2] / UNIT_HEIGHT);
	Verb_Printf(VERB_NORMAL, "       Number of entities: %i\n", num_entities);

	/* count number of each type of entity */
	for (int i = 0; i < num_entities; i++) {
		const char* name = ValueForKey(&entities[i], "classname");

		for (j = 0; j < numEntityDefs; j++)
			if (Q_streq(name, entityDefs[j].classname)) {
				entNums[j]++;
				break;
			}
		if (j == numEntityDefs) {
			Com_Printf("Check_Stats: entity '%s' not recognised\n", name);
		}
	}

	/* print number of each type of entity */
	for (j = 0; j < numEntityDefs; j++)
		if (entNums[j])
			Com_Printf("%27s: %i\n", entityDefs[j].classname, entNums[j]);

	Mem_Free(entNums);
}
Exemplo n.º 25
0
/**
 * @brief Fills in texorg, worldtotex. and textoworld
 */
static void CalcLightinfoVectors (lightinfo_t* l)
{
	const dBspTexinfo_t* tex;
	int i;
	vec3_t texnormal;
	vec_t distscale, dist;

	tex = &curTile->texinfo[l->face->texinfo];

	for (i = 0; i < 2; i++)
		VectorCopy(tex->vecs[i], l->worldtotex[i]);

	/* calculate a normal to the texture axis.  points can be moved along this
	 * without changing their S/T */
	texnormal[0] = tex->vecs[1][1] * tex->vecs[0][2]
					- tex->vecs[1][2] * tex->vecs[0][1];
	texnormal[1] = tex->vecs[1][2] * tex->vecs[0][0]
					- tex->vecs[1][0] * tex->vecs[0][2];
	texnormal[2] = tex->vecs[1][0] * tex->vecs[0][1]
					- tex->vecs[1][1] * tex->vecs[0][0];
	VectorNormalize(texnormal);

	/* flip it towards plane normal */
	distscale = DotProduct(texnormal, l->facenormal);
	if (!distscale) {
		Verb_Printf(VERB_EXTRA, "WARNING: Texture axis perpendicular to face\n");
		distscale = 1.0;
	}
	if (distscale < 0.0) {
		distscale = -distscale;
		VectorSubtract(vec3_origin, texnormal, texnormal);
	}

	/* distscale is the ratio of the distance along the texture normal to
	 * the distance along the plane normal */
	distscale = 1.0 / distscale;

	for (i = 0; i < 2; i++) {
		const vec_t len = VectorLength(l->worldtotex[i]);
		const vec_t distance = DotProduct(l->worldtotex[i], l->facenormal) * distscale;
		VectorMA(l->worldtotex[i], -distance, texnormal, l->textoworld[i]);
		VectorScale(l->textoworld[i], (1.0f / len) * (1.0f / len), l->textoworld[i]);
	}

	/* calculate texorg on the texture plane */
	for (i = 0; i < 3; i++)
		l->texorg[i] =
			-tex->vecs[0][3] * l->textoworld[0][i] -
			tex->vecs[1][3] * l->textoworld[1][i];

	/* project back to the face plane */
	dist = DotProduct(l->texorg, l->facenormal) - l->facedist - 1;
	dist *= distscale;
	VectorMA(l->texorg, -dist, texnormal, l->texorg);

	/* compensate for org'd bmodels */
	VectorAdd(l->texorg, l->modelorg, l->texorg);

	/* total sample count */
	l->numsurfpt = l->texsize[0] * l->texsize[1];
	l->surfpt = Mem_AllocTypeN(vec3_t, l->numsurfpt);
	if (!l->surfpt)
		Sys_Error("Surface too large to light (" UFO_SIZE_T ")", l->numsurfpt * sizeof(*l->surfpt));

	/* distance between samples */
	l->step = 1 << config.lightquant;
}
Exemplo n.º 26
0
/**
 * @sa WriteMapFile
 * @sa ParseMapEntity
 */
void LoadMapFile (const char* filename)
{
	Verb_Printf(VERB_EXTRA, "--- LoadMapFile ---\n");

	LoadScriptFile(filename);

	OBJZERO(mapbrushes);
	nummapbrushes = 0;

	OBJZERO(brushsides);
	nummapbrushsides = 0;

	OBJZERO(side_brushtextures);

	OBJZERO(mapplanes);

	num_entities = 0;
	/* Create this shortcut to mapTiles[0] */
	curTile = &mapTiles.mapTiles[0];
	/* Set the number of tiles to 1. This is fix for ufo2map right now. */
	mapTiles.numTiles = 1;

	char entityString[MAX_TOKEN_CHARS];
	const char* ump = GetUMPName(filename);
	if (ump != nullptr)
		ParseUMP(ump, entityString, false);

	while (ParseMapEntity(filename, entityString));

	int subdivide = atoi(ValueForKey(&entities[0], "subdivide"));
	if (subdivide >= 256 && subdivide <= 2048) {
		Verb_Printf(VERB_EXTRA, "Using subdivide %d from worldspawn.\n", subdivide);
		config.subdivideSize = subdivide;
	}

	if (footstepsCnt)
		Com_Printf("Generated footstep file with %i entries\n", footstepsCnt);
	if (materialsCnt)
		Com_Printf("Generated material file with %i entries\n", materialsCnt);

	vec3_t map_mins, map_maxs;
	ClearBounds(map_mins, map_maxs);
	for (int i = 0; i < entities[0].numbrushes; i++) {
		if (mapbrushes[i].mbBox.mins[0] > MAX_WORLD_WIDTH)
			continue;	/* no valid points */
		AddPointToBounds(mapbrushes[i].mbBox.mins, map_mins, map_maxs);
		AddPointToBounds(mapbrushes[i].mbBox.maxs, map_mins, map_maxs);
	}

	/* save a copy of the brushes */
	memcpy(mapbrushes + nummapbrushes, mapbrushes, sizeof(mapbrush_t) * nummapbrushes);

	Verb_Printf(VERB_EXTRA, "%5i brushes\n", nummapbrushes);
	Verb_Printf(VERB_EXTRA, "%5i total sides\n", nummapbrushsides);
	Verb_Printf(VERB_EXTRA, "%5i boxbevels\n", c_boxbevels);
	Verb_Printf(VERB_EXTRA, "%5i edgebevels\n", c_edgebevels);
	Verb_Printf(VERB_EXTRA, "%5i entities\n", num_entities);
	Verb_Printf(VERB_EXTRA, "%5i planes\n", nummapplanes);
	Verb_Printf(VERB_EXTRA, "size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n",
		map_mins[0], map_mins[1], map_mins[2], map_maxs[0], map_maxs[1], map_maxs[2]);
}
Exemplo n.º 27
0
/**
 * @brief Generates two new brushes, leaving the original unchanged
 */
void SplitBrush (const bspbrush_t* brush, uint16_t planenum, bspbrush_t** front, bspbrush_t** back)
{
	bspbrush_t* b[2];
	int i, j;
	winding_t* w, *cw[2], *midwinding;
	plane_t* plane;
	float d_front, d_back;

	*front = *back = nullptr;
	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++) {
			const float d = DotProduct(w->p[j], plane->normal) - plane->dist;
			if (d > 0 && d > d_front)
				d_front = d;
			else 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++) {
		plane_t* plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
		ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); /* PLANESIDE_EPSILON); */
	}

	/* the brush isn't really split */
	if (!w || WindingIsTiny(w)) {
		const int side = BrushMostlyOnSide(brush, plane);
		if (side == PSIDE_FRONT)
			*front = CopyBrush(brush);
		else if (side == PSIDE_BACK)
			*back = CopyBrush(brush);
		return;
	}

	if (WindingIsHuge(w)) {
		/** @todo Print brush and entnum either of the brush that was splitted
		 * or the plane that was used as splitplane */
		Com_Printf("WARNING: Large winding\n");
	}

	midwinding = w;

	/* split it for real */
	for (i = 0; i < 2; i++) {
		b[i] = AllocBrush(brush->numsides + 1);
		b[i]->original = brush->original;
	}

	/* split all the current windings */
	for (i = 0; i < brush->numsides; i++) {
		const side_t* s = &brush->sides[i];
		w = s->winding;
		if (!w)
			continue;
		ClipWindingEpsilon(w, plane->normal, plane->dist,
			0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
		for (j = 0; j < 2; j++) {
			side_t* cs;

			if (!cw[j])
				continue;

			cs = &b[j]->sides[b[j]->numsides];
			b[j]->numsides++;
			*cs = *s;

			cs->winding = cw[j];
			cs->tested = false;
		}
	}

	/* see if we have valid polygons on both sides */
	for (i = 0; i < 2; i++) {
		BoundBrush(b[i]);
		for (j = 0; j < 3; j++) {
			if (b[i]->mins[j] < -MAX_WORLD_WIDTH || b[i]->maxs[j] > MAX_WORLD_WIDTH) {
				/** @todo Print brush and entnum either of the brush that was split
				 * or the plane that was used as splitplane */
				Verb_Printf(VERB_EXTRA, "bogus brush after clip\n");
				break;
			}
		}

		if (b[i]->numsides < 3 || j < 3) {
			FreeBrush(b[i]);
			b[i] = nullptr;
		}
	}

	if (!(b[0] && b[1])) {
		/** @todo Print brush and entnum either of the brush that was splitted
		 * or the plane that was used as splitplane */
		if (!b[0] && !b[1])
			Verb_Printf(VERB_EXTRA, "split removed brush\n");
		else
			Verb_Printf(VERB_EXTRA, "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++) {
		side_t* cs = &b[i]->sides[b[i]->numsides];
		b[i]->numsides++;

		cs->planenum = planenum ^ i ^ 1;
		cs->texinfo = TEXINFO_NODE;
		cs->visible = false;
		cs->tested = false;
		if (i == 0)
			cs->winding = CopyWinding(midwinding);
		else
			cs->winding = midwinding;
	}

	for (i = 0; i < 2; i++) {
		const vec_t v1 = BrushVolume(b[i]);
		if (v1 < 1.0) {
			FreeBrush(b[i]);
			b[i] = nullptr;
			/** @todo Print brush and entnum either of the brush that was splitted
			 * or the plane that was used as splitplane */
			Verb_Printf(VERB_EXTRA, "tiny volume after clip\n");
		}
	}

	*front = b[0];
	*back = b[1];
}
Exemplo n.º 28
0
/**
 * @brief Parses a brush from the map file
 * @sa FindMiptex
 * @param[in] mapent The entity the brush to parse belongs to
 * @param[in] filename The map filename, used to derive the name for the footsteps file
 */
static void ParseBrush (entity_t* mapent, const char* filename)
{
	int j, k;
	brush_texture_t td;
	vec3_t planepts[3];
	const int checkOrFix = config.performMapCheck || config.fixMap ;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		b->mbBox.getCenter(origin);

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

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

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

		return;
	}

	if (!checkOrFix)
		AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
}
Exemplo n.º 29
0
/**
 * @sa ProcessLevel
 * @return The node num
 */
static int32_t ConstructLevelNodes_r (const int levelnum, const vec3_t cmins, const vec3_t cmaxs, int entityNum)
{
	bspbrush_t *list;
	tree_t *tree;
	vec3_t diff, bmins, bmaxs;
	int32_t nn[3];
	node_t *node;

	/* calculate bounds, stop if no brushes are available */
	if (!MapBrushesBounds(brush_start, brush_end, levelnum, cmins, cmaxs, bmins, bmaxs))
		return LEAFNODE;

	Verb_Printf(VERB_DUMP, "ConstructLevelNodes_r: lv=%i (%f %f %f) (%f %f %f)\n", levelnum,
		cmins[0], cmins[1], cmins[2], cmaxs[0], cmaxs[1], cmaxs[2]);

	VectorSubtract(bmaxs, bmins, diff);

/*	Com_Printf("(%i): %i %i: (%i %i) (%i %i) -> (%i %i) (%i %i)\n", levelnum, (int)diff[0], (int)diff[1],
		(int)cmins[0], (int)cmins[1], (int)cmaxs[0], (int)cmaxs[1],
		(int)bmins[0], (int)bmins[1], (int)bmaxs[0], (int)bmaxs[1]); */

	if (diff[0] > SPLIT_BRUSH_SIZE || diff[1] > SPLIT_BRUSH_SIZE) {
		/* continue subdivision */
		/* split the remaining hull at the middle of the longer axis */
		vec3_t nmins, nmaxs;
		int n;

		if (diff[1] > diff[0])
			n = 1;
		else
			n = 0;

		VectorCopy(bmins, nmins);
		VectorCopy(bmaxs, nmaxs);

		nmaxs[n] -= diff[n] / 2;
/*		Com_Printf("  (%i %i) (%i %i)\n", (int)nmins[0], (int)nmins[1], (int)nmaxs[0], (int)nmaxs[1]); */
		nn[0] = ConstructLevelNodes_r(levelnum, nmins, nmaxs, entityNum);

		nmins[n] += diff[n] / 2;
		nmaxs[n] += diff[n] / 2;
/*		Com_Printf("    (%i %i) (%i %i)\n", (int)nmins[0], (int)nmins[1], (int)nmaxs[0], (int)nmaxs[1]); */
		nn[1] = ConstructLevelNodes_r(levelnum, nmins, nmaxs, entityNum);
	} else {
		/* no children */
		nn[0] = LEAFNODE;
		nn[1] = LEAFNODE;
	}

	/* add v_epsilon to avoid clipping errors */
	VectorSubtract(bmins, v_epsilon, bmins);
	VectorAdd(bmaxs, v_epsilon, bmaxs);

	/* Call BeginModel only to initialize brush pointers */
	BeginModel(entityNum);

	list = MakeBspBrushList(brush_start, brush_end, levelnum, bmins, bmaxs);
	if (!list) {
		nn[2] = LEAFNODE;
		return BuildNodeChildren(nn);
	}

	if (!config.nocsg)
		list = ChopBrushes(list);

	/* begin model creation now */
	tree = BuildTree(list, bmins, bmaxs);
	MakeTreePortals(tree);
	MarkVisibleSides(tree, brush_start, brush_end);
	MakeFaces(tree->headnode);
	FixTjuncs(tree->headnode);

	if (!config.noprune)
		PruneNodes(tree->headnode);

	/* correct bounds */
	node = tree->headnode;
	VectorAdd(bmins, v_epsilon, node->mins);
	VectorSubtract(bmaxs, v_epsilon, node->maxs);

	/* finish model */
	nn[2] = WriteBSP(tree->headnode);
	FreeTree(tree);

	/* Store created nodes */
	return BuildNodeChildren(nn);
}
Exemplo n.º 30
0
/**
 * @brief Create lights out of patches and entity lights
 * @sa LightWorld
 * @sa BuildPatch
 */
void BuildLights (void)
{
	int i;
	light_t* l;

	/* surfaces */
	for (i = 0; i < MAX_MAP_FACES; i++) {
		/* iterate subdivided patches */
		for(const patch_t* p = face_patches[i]; p; p = p->next) {
			if (VectorEmpty(p->light))
				continue;

			numlights[config.compile_for_day]++;
			l = Mem_AllocType(light_t);

			VectorCopy(p->origin, l->origin);

			l->next = lights[config.compile_for_day];
			lights[config.compile_for_day] = l;

			l->type = emit_surface;

			l->intensity = ColorNormalize(p->light, l->color);
			l->intensity *= p->area * config.surface_scale;
		}
	}

	/* entities (skip the world) */
	for (i = 1; i < num_entities; i++) {
		float intensity;
		const char* color;
		const char* target;
		const entity_t* e = &entities[i];
		const char* name = ValueForKey(e, "classname");
		if (!Q_strstart(name, "light"))
			continue;

		/* remove those lights that are only for the night version */
		if (config.compile_for_day) {
			const int spawnflags = atoi(ValueForKey(e, "spawnflags"));
			if (!(spawnflags & 1))	/* day */
				continue;
		}

		numlights[config.compile_for_day]++;
		l = Mem_AllocType(light_t);

		GetVectorForKey(e, "origin", l->origin);

		/* link in */
		l->next = lights[config.compile_for_day];
		lights[config.compile_for_day] = l;

		intensity = FloatForKey(e, "light");
		if (!intensity)
			intensity = 300.0;
		color = ValueForKey(e, "_color");
		if (color && color[0] != '\0'){
			if (sscanf(color, "%f %f %f", &l->color[0], &l->color[1], &l->color[2]) != 3)
				Sys_Error("Invalid _color entity property given: %s", color);
			ColorNormalize(l->color, l->color);
		} else
			VectorSet(l->color, 1.0, 1.0, 1.0);
		l->intensity = intensity * config.entity_scale;
		l->type = emit_point;

		target = ValueForKey(e, "target");
		if (target[0] != '\0' || Q_streq(name, "light_spot")) {
			l->type = emit_spotlight;
			l->stopdot = FloatForKey(e, "_cone");
			if (!l->stopdot)
				l->stopdot = 10;
			l->stopdot = cos(l->stopdot * torad);
			if (target[0] != '\0') {	/* point towards target */
				entity_t* e2 = FindTargetEntity(target);
				if (!e2)
					Com_Printf("WARNING: light at (%i %i %i) has missing target '%s' - e.g. create an info_null that has a 'targetname' set to '%s'\n",
						(int)l->origin[0], (int)l->origin[1], (int)l->origin[2], target, target);
				else {
					vec3_t dest;
					GetVectorForKey(e2, "origin", dest);
					VectorSubtract(dest, l->origin, l->normal);
					VectorNormalize(l->normal);
				}
			} else {	/* point down angle */
				const float angle = FloatForKey(e, "angle");
				if (angle == ANGLE_UP) {
					l->normal[0] = l->normal[1] = 0.0;
					l->normal[2] = 1.0;
				} else if (angle == ANGLE_DOWN) {
					l->normal[0] = l->normal[1] = 0.0;
					l->normal[2] = -1.0;
				} else {
					l->normal[2] = 0;
					l->normal[0] = cos(angle * torad);
					l->normal[1] = sin(angle * torad);
				}
			}
		}
	}

	/* handle worldspawn light settings */
	{
		const entity_t* e = &entities[0];
		const char* ambient, *light, *angles, *color;
		float f;
		int i;

		if (config.compile_for_day) {
			ambient = ValueForKey(e, "ambient_day");
			light = ValueForKey(e, "light_day");
			angles = ValueForKey(e, "angles_day");
			color = ValueForKey(e, "color_day");
		} else {
			ambient = ValueForKey(e, "ambient_night");
			light = ValueForKey(e, "light_night");
			angles = ValueForKey(e, "angles_night");
			color = ValueForKey(e, "color_night");
		}

		if (light[0] != '\0')
			sun_intensity = atoi(light);

		if (angles[0] != '\0') {
			VectorClear(sun_angles);
			if (sscanf(angles, "%f %f", &sun_angles[0], &sun_angles[1]) != 2)
				Sys_Error("wrong angles values given: '%s'", angles);
			AngleVectors(sun_angles, sun_normal, nullptr, nullptr);
		}

		if (color[0] != '\0') {
			GetVectorFromString(color, sun_color);
			ColorNormalize(sun_color, sun_color);
		}

		if (ambient[0] != '\0')
			GetVectorFromString(ambient, sun_ambient_color);

		/* optionally pull brightness from worldspawn */
		f = FloatForKey(e, "brightness");
		if (f > 0.0)
			config.brightness = f;

		/* saturation as well */
		f = FloatForKey(e, "saturation");
		if (f > 0.0)
			config.saturation = f;
		else
			Verb_Printf(VERB_EXTRA, "Invalid saturation setting (%f) in worldspawn found\n", f);

		f = FloatForKey(e, "contrast");
		if (f > 0.0)
			config.contrast = f;
		else
			Verb_Printf(VERB_EXTRA, "Invalid contrast setting (%f) in worldspawn found\n", f);

		/* lightmap resolution downscale (e.g. 4 = 1 << 4) */
		i = atoi(ValueForKey(e, "quant"));
		if (i >= 1 && i <= 6)
			config.lightquant = i;
		else
			Verb_Printf(VERB_EXTRA, "Invalid quant setting (%i) in worldspawn found\n", i);
	}

	Verb_Printf(VERB_EXTRA, "light settings:\n * intensity: %i\n * sun_angles: pitch %f yaw %f\n * sun_color: %f:%f:%f\n * sun_ambient_color: %f:%f:%f\n",
		sun_intensity, sun_angles[0], sun_angles[1], sun_color[0], sun_color[1], sun_color[2], sun_ambient_color[0], sun_ambient_color[1], sun_ambient_color[2]);
	Verb_Printf(VERB_NORMAL, "%i direct lights for %s lightmap\n", numlights[config.compile_for_day], (config.compile_for_day ? "day" : "night"));
}