Exemple #1
0
/*
 * @brief Mark each leaf with an area, bounded by CONTENTS_AREA_PORTAL
 */
void FloodAreas(tree_t *tree) {

    Com_Verbose("--- FloodAreas ---\n");
    FindAreas_r(tree->head_node);

    SetAreaPortalAreas_r(tree->head_node);
    Com_Verbose("%5i areas\n", c_areas);
}
Exemple #2
0
/*
 * =============
 * FillOutside
 *
 * Fill all nodes that can't be reached by entities
 * =============
 */
void FillOutside(node_t * head_node) {
    c_outside = 0;
    c_inside = 0;
    c_solid = 0;
    Com_Verbose("--- FillOutside ---\n");
    FillOutside_r(head_node);
    Com_Verbose("%5i solid leafs\n", c_solid);
    Com_Verbose("%5i leafs filled\n", c_outside);
    Com_Verbose("%5i inside leafs\n", c_inside);
}
Exemple #3
0
/*
 * @brief
 */
void WriteBSP(node_t *head_node) {
	int32_t old_faces;

	c_nofaces = 0;
	c_facenodes = 0;

	Com_Verbose("--- WriteBSP ---\n");

	old_faces = d_bsp.num_faces;

	d_bsp.models[d_bsp.num_models].head_node = EmitDrawNode_r(head_node);

	Com_Verbose("%5i nodes with faces\n", c_facenodes);
	Com_Verbose("%5i nodes without faces\n", c_nofaces);
	Com_Verbose("%5i faces\n", d_bsp.num_faces - old_faces);
}
Exemple #4
0
/**
 * @brief Send the servers list to the specified client address.
 */
static void Ms_GetServers(struct sockaddr_in *from) {
	mem_buf_t buf;
	byte buffer[0xffff];

	Mem_InitBuffer(&buf, buffer, sizeof(buffer));

	const char *servers = "\xFF\xFF\xFF\xFF" "servers ";
	Mem_WriteBuffer(&buf, servers, strlen(servers));

	uint32_t i = 0;
	GList *s = ms_servers;
	while (s) {
		const ms_server_t *server = (ms_server_t *) s->data;
		if (server->validated) {
			Mem_WriteBuffer(&buf, &server->addr.sin_addr, sizeof(server->addr.sin_addr));
			Mem_WriteBuffer(&buf, &server->addr.sin_port, sizeof(server->addr.sin_port));
			i++;
		}
		s = s->next;
	}

	if ((sendto(ms_sock, buf.data, buf.size, 0, (struct sockaddr *) from, sizeof(*from))) == -1) {
		Com_Warn("%s: %s\n", atos(from), strerror(errno));
	} else {
		Com_Verbose("Sent %d servers to %s\n", i, atos(from));
	}
}
Exemple #5
0
/**
 * @brief
 */
static void Ms_Frame(void) {
	const time_t now = time(NULL);

	GList *s = ms_servers;
	while (s) {
		ms_server_t *server = (ms_server_t *) s->data;
		if (now - server->last_heartbeat > 30) {

			if (server->queued_pings > 6) {
				Com_Print("Server %s timed out\n", stos(server));
				Ms_DropServer(server);
			} else {
				if (now - server->last_ping >= 10) {
					server->queued_pings++;
					server->last_ping = now;

					Com_Verbose("Pinging %s\n", stos(server));

					const char *ping = "\xFF\xFF\xFF\xFF" "ping";
					sendto(ms_sock, ping, strlen(ping), 0, (struct sockaddr *) &server->addr,
					       sizeof(server->addr));
				}
			}
		}

		s = s->next;
	}
}
Exemple #6
0
/*
 * @brief
 */
static int32_t BrushContents(const map_brush_t * b) {
	int32_t contents;
	const side_t *s;
	int32_t i;
	int32_t trans;

	s = &b->original_sides[0];
	contents = s->contents;
	trans = d_bsp.texinfo[s->texinfo].flags;
	for (i = 1; i < b->num_sides; i++, s++) {
		trans |= d_bsp.texinfo[s->texinfo].flags;
		if (s->contents != contents) {
			Com_Verbose("Entity %i, Brush %i: mixed face contents\n", b->entity_num, b->brush_num);
			break;
		}
	}

	// if any side is translucent, mark the contents and change solid to window
	if (trans & (SURF_ALPHA_TEST | SURF_BLEND_33 | SURF_BLEND_66)) {
		contents |= CONTENTS_TRANSLUCENT;
		if (contents & CONTENTS_SOLID) {
			contents &= ~CONTENTS_SOLID;
			contents |= CONTENTS_WINDOW;
		}
	}

	return contents;
}
Exemple #7
0
/*
 * @brief
 */
void WritePortalFile(tree_t *tree) {
    char filename[MAX_OSPATH];
    node_t *head_node;

    Com_Verbose("--- WritePortalFile ---\n");

    head_node = tree->head_node;
    num_visclusters = 0;
    num_visportals = 0;

    FreeTreePortals_r(head_node);

    MakeHeadnodePortals(tree);

    CreateVisPortals_r(head_node);

    // set the cluster field in every leaf and count the total number of portals
    NumberLeafs_r(head_node);

    // write the file
    StripExtension(map_name, filename);
    strcat(filename, ".prt");

    if (!(prtfile = Fs_OpenWrite(filename)))
        Com_Error(ERR_FATAL, "Error opening %s\n", filename);

    Fs_Print(prtfile, "%s\n", PORTALFILE);
    Fs_Print(prtfile, "%i\n", num_visclusters);
    Fs_Print(prtfile, "%i\n", num_visportals);

    Com_Verbose("%5i visclusters\n", num_visclusters);
    Com_Verbose("%5i visportals\n", num_visportals);

    WritePortalFile_r(head_node);

    Fs_Close(prtfile);

    // we need to store the clusters out now because ordering
    // issues made us do this after writebsp...
    clusterleaf = 1;
    SaveClusters_r(head_node);

    Com_Verbose("--- WritePortalFile complete ---\n");
}
Exemple #8
0
/*
 * MakeBrushWindings
 *
 * Makes basewindigs for sides and mins / maxs for the brush
 */
static boolean_t MakeBrushWindings(map_brush_t * ob) {
	int i, j;
	side_t *side;

	ClearBounds(ob->mins, ob->maxs);

	for (i = 0; i < ob->num_sides; i++) {
		const map_plane_t *plane = &map_planes[ob->original_sides[i].plane_num];
		winding_t *w = BaseWindingForPlane(plane->normal, plane->dist);
		for (j = 0; j < ob->num_sides && w; j++) {
			if (i == j)
				continue;
			// back side clipaway
			if (ob->original_sides[j].plane_num
					== (ob->original_sides[j].plane_num ^ 1))
				continue;
			if (ob->original_sides[j].bevel)
				continue;
			plane = &map_planes[ob->original_sides[j].plane_num ^ 1];
			ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
		}

		side = &ob->original_sides[i];
		side->winding = w;
		if (w) {
			side->visible = true;
			for (j = 0; j < w->numpoints; j++)
				AddPointToBounds(w->p[j], ob->mins, ob->maxs);
		}
	}

	for (i = 0; i < 3; i++) {
		if (ob->mins[0] < -MAX_WORLD_WIDTH || ob->maxs[0] > MAX_WORLD_WIDTH)
			Com_Verbose("entity %i, brush %i: bounds out of range\n",
					ob->entity_num, ob->brush_num);
		if (ob->mins[0] > MAX_WORLD_WIDTH || ob->maxs[0] < -MAX_WORLD_WIDTH)
			Com_Verbose("entity %i, brush %i: no visible sides on brush\n",
					ob->entity_num, ob->brush_num);
	}

	return true;
}
Exemple #9
0
/*
 * ============
 * FindPortalSide
 *
 * Finds a brush side to use for texturing the given portal
 * ============
 */
static void FindPortalSide(portal_t * p) {
    int32_t viscontents;
    bsp_brush_t *bb;
    int32_t i, j;
    int32_t plane_num;
    side_t *bestside;
    vec_t dot, bestdot;
    map_plane_t *p2;

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

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

    for (j = 0; j < 2; j++) {
        const node_t *n = p->nodes[j];
        const map_plane_t *p1 = &map_planes[p->onnode->plane_num];
        for (bb = n->brushes; bb; bb = bb->next) {
            const map_brush_t *brush = bb->original;
            if (!(brush->contents & viscontents))
                continue;
            for (i = 0; i < brush->num_sides; i++) {
                side_t *side = &brush->original_sides[i];
                if (side->bevel)
                    continue;
                if (side->texinfo == TEXINFO_NODE)
                    continue; // non-visible
                if ((side->plane_num & ~1) == plane_num) { // exact match
                    bestside = &brush->original_sides[i];
                    goto gotit;
                }
                // see how close the match is
                p2 = &map_planes[side->plane_num & ~1];
                dot = DotProduct(p1->normal, p2->normal);
                if (dot > bestdot) {
                    bestdot = dot;
                    bestside = side;
                }
            }
        }
    }

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

    p->sidefound = true;
    p->side = bestside;
}
Exemple #10
0
/*
 * @brief Calculate the PHS (Potentially Hearable Set)
 * by ORing together all the PVS visible from a leaf
 */
static void CalcPHS(void) {
	uint32_t i, j, k, l, index;
	int32_t bitbyte;
	long *dest, *src;
	byte *scan;
	int32_t count;
	byte uncompressed[MAX_BSP_LEAFS / 8];
	byte compressed[MAX_BSP_LEAFS / 8];

	Com_Verbose("Building PHS...\n");

	count = 0;
	for (i = 0; i < map_vis.portal_clusters; i++) {
		scan = map_vis.uncompressed + i * map_vis.leaf_bytes;
		memcpy(uncompressed, scan, map_vis.leaf_bytes);
		for (j = 0; j < map_vis.leaf_bytes; j++) {
			bitbyte = scan[j];
			if (!bitbyte)
				continue;
			for (k = 0; k < 8; k++) {
				if (!(bitbyte & (1 << k)))
					continue;
				// OR this pvs row into the phs
				index = ((j << 3) + k);
				if (index >= map_vis.portal_clusters)
					Com_Error(ERR_FATAL, "Bad bit vector in PVS\n"); // pad bits should be 0
				src = (long *) (map_vis.uncompressed + index * map_vis.leaf_bytes);
				for (l = 0; l < map_vis.leaf_longs; l++)
					((long *) uncompressed)[l] |= src[l];
			}
		}
		for (j = 0; j < map_vis.portal_clusters; j++)
			if (uncompressed[j >> 3] & (1 << (j & 7)))
				count++;

		// compress the bit string
		j = CompressVis(uncompressed, compressed);

		dest = (long *) map_vis.pointer;
		map_vis.pointer += j;

		if (map_vis.pointer > map_vis.end)
			Com_Error(ERR_FATAL, "Overflow\n");

		d_vis->bit_offsets[i][DVIS_PHS] = (byte *) dest - map_vis.base;

		memcpy(dest, compressed, j);
	}

	if (map_vis.portal_clusters)
		Com_Print("Average clusters hearable: %i\n", count / map_vis.portal_clusters);
	else
		Com_Print("Average clusters hearable: 0\n");
}
Exemple #11
0
/**
 * @brief
 */
void CalcTextureReflectivity(void) {
	char path[MAX_OS_PATH];
	int32_t i, j, texels;
	uint32_t color[3];
	SDL_Surface *surf;

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

	for (i = 0; i < bsp_file.num_texinfo; i++) {

		// see if an earlier texinfo already got the value
		for (j = 0; j < i; j++) {
			if (!g_strcmp0(bsp_file.texinfo[i].texture, bsp_file.texinfo[j].texture)) {
				VectorCopy(texture_reflectivity[j], texture_reflectivity[i]);
				break;
			}
		}

		if (j != i) { // earlier texinfo found, continue
			continue;
		}

		// load the image to calculate reflectivity
		g_snprintf(path, sizeof(path), "textures/%s", bsp_file.texinfo[i].texture);

		if (!Img_LoadImage(path, &surf)) {
			Com_Warn("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
		}

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

		SDL_FreeSurface(surf);

		for (j = 0; j < 3; j++) {
			const vec_t r = color[j] / texels / 255.0;
			texture_reflectivity[i][j] = r;
		}
	}
}
Exemple #12
0
/**
 * @brief Acknowledge the server from the specified address.
 */
static void Ms_Ack(struct sockaddr_in *from) {
	ms_server_t *server = Ms_GetServer(from);

	if (server) {
		Com_Verbose("Ack from %s (%d)\n", stos(server), server->queued_pings);

		server->validated = true;
		server->queued_pings = 0;

	} else {
		Com_Warn("Ack from unregistered server %s\n", atos(from));
	}
}
Exemple #13
0
/**
 * @brief Accept a "heartbeat" from the specified server address.
 */
static void Ms_Heartbeat(struct sockaddr_in *from) {
	ms_server_t *server = Ms_GetServer(from);

	if (server) {
		server->last_heartbeat = time(NULL);

		Com_Verbose("Heartbeat from %s\n", stos(server));

		const void *ack = "\xFF\xFF\xFF\xFF" "ack";
		sendto(ms_sock, ack, 7, 0, (struct sockaddr *) &server->addr, sizeof(server->addr));
	} else {
		Ms_AddServer(from);
	}
}
Exemple #14
0
/*
 * @brief
 */
static void MakeTreePortals_r(node_t * node) {
    int32_t i;

    CalcNodeBounds(node);
    if (node->mins[0] >= node->maxs[0]) {
        Com_Verbose("WARNING: node without a volume\n");
    }

    for (i = 0; i < 3; i++) {
        if (node->mins[i] < -8000 || node->maxs[i] > 8000) {
            Com_Verbose("WARNING: node with unbounded volume\n");
            break;
        }
    }
    if (node->plane_num == PLANENUM_LEAF)
        return;

    MakeNodePortal(node);
    SplitNodePortals(node);

    MakeTreePortals_r(node->children[0]);
    MakeTreePortals_r(node->children[1]);
}
Exemple #15
0
/*
 * @brief
 */
void EmitAreaPortals(void) {
    int32_t i, j;
    d_bsp_area_portal_t *dp;

    if (c_areas > MAX_BSP_AREAS)
        Com_Error(ERR_FATAL, "MAX_BSP_AREAS\n");

    d_bsp.num_areas = c_areas + 1;
    d_bsp.num_area_portals = 1; // leave 0 as an error

    for (i = 1; i <= c_areas; i++) {
        d_bsp.areas[i].first_area_portal = d_bsp.num_area_portals;
        for (j = 0; j < num_entities; j++) {
            const entity_t *e = &entities[j];

            if (!e->area_portal_num)
                continue;

            dp = &d_bsp.area_portals[d_bsp.num_area_portals];

            if (e->portal_areas[0] == i) {
                dp->portal_num = e->area_portal_num;
                dp->other_area = e->portal_areas[1];
                d_bsp.num_area_portals++;
            } else if (e->portal_areas[1] == i) {
                dp->portal_num = e->area_portal_num;
                dp->other_area = e->portal_areas[0];
                d_bsp.num_area_portals++;
            }
        }
        d_bsp.areas[i].num_area_portals = d_bsp.num_area_portals - d_bsp.areas[i].first_area_portal;
    }

    Com_Verbose("%5i num_areas\n", d_bsp.num_areas);
    Com_Verbose("%5i num_area_portals\n", d_bsp.num_area_portals);
}
Exemple #16
0
/*
 * @brief
 */
void EndBSPFile(void) {

	EmitBrushes();
	EmitPlanes();
	EmitAreaPortals();

	UnparseEntities();

	// now that the verts have been resolved, align the normals count
	d_bsp.num_normals = d_bsp.num_vertexes;

	// write the map
	Com_Verbose("Writing %s\n", bsp_name);
	WriteBSPFile(bsp_name);
}
Exemple #17
0
/*
 * =============
 * MarkVisibleSides
 *
 * =============
 */
void MarkVisibleSides(tree_t * tree, int32_t startbrush, int32_t endbrush) {
    int32_t i, j;

    Com_Verbose("--- MarkVisibleSides ---\n");

    // clear all the visible flags
    for (i = startbrush; i < endbrush; i++) {
        map_brush_t *mb = &map_brushes[i];
        const int32_t num_sides = mb->num_sides;
        for (j = 0; j < num_sides; j++)
            mb->original_sides[j].visible = false;
    }

    // set visible flags on the sides that are used by portals
    MarkVisibleSides_r(tree->head_node);
}
Exemple #18
0
/*
 * @brief
 */
static void FloodAreas_r(node_t * node) {
    portal_t *p;
    int32_t s;

    if (node->contents == CONTENTS_AREA_PORTAL) {
        // this node is part of an area portal
        const bsp_brush_t *b = node->brushes;
        entity_t *e = &entities[b->original->entity_num];

        // if the current area has already touched this
        // portal, we are done
        if (e->portal_areas[0] == c_areas || e->portal_areas[1] == c_areas)
            return;

        // note the current area as bounding the portal
        if (e->portal_areas[1]) {
            Com_Verbose("WARNING: areaportal entity %i touches > 2 areas\n",
                        b->original->entity_num);
            return;
        }
        if (e->portal_areas[0])
            e->portal_areas[1] = c_areas;
        else
            e->portal_areas[0] = c_areas;

        return;
    }

    if (node->area)
        return; // already got it
    node->area = c_areas;

    for (p = node->portals; p; p = p->next[s]) {
        s = (p->nodes[1] == node);
        // TODO: why is this commented out?
#if 0
        if(points->nodes[!s]->occupied)
            continue;
#endif
        if (!Portal_EntityFlood(p))
            continue;

        FloodAreas_r(p->nodes[!s]);
    }
}
Exemple #19
0
/*
 * @brief
 */
static void ProcessModels(void) {
	BeginBSPFile();

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

		Com_Verbose("############### model %i ###############\n", d_bsp.num_models);
		BeginModel();
		if (entity_num == 0)
			ProcessWorldModel();
		else
			ProcessSubModel();
		EndModel();
	}

	EndBSPFile();
}
Exemple #20
0
/*
 * EndOfScript
 */
static boolean_t EndOfScript(boolean_t crossline){
	if(!crossline)
		Com_Error(ERR_FATAL, "EndOfScript: Line %i is incomplete\n", scriptline);

	if(!strcmp(script->file_name, "memory buffer")){
		endofscript = true;
		return false;
	}

	Z_Free(script->buffer);
	if(script == scriptstack + 1){
		endofscript = true;
		return false;
	}
	script--;
	scriptline = script->line;
	Com_Verbose("returning to %s\n", script->file_name);
	return GetToken(crossline);
}
Exemple #21
0
static void ProcessBlock_Thread(int blocknum){
	int xblock, yblock;
	vec3_t mins, maxs;
	bsp_brush_t *brushes;
	tree_t *tree;
	node_t *node;

	yblock = block_yl + blocknum / (block_xh - block_xl + 1);
	xblock = block_xl + blocknum % (block_xh - block_xl + 1);

	Com_Verbose("############### block %2i,%2i ###############\n",
	            xblock, yblock);

	mins[0] = xblock * 1024;
	mins[1] = yblock * 1024;
	mins[2] = -MAX_WORLD_WIDTH;
	maxs[0] = (xblock + 1) * 1024;
	maxs[1] = (yblock + 1) * 1024;
	maxs[2] = MAX_WORLD_WIDTH;

	ThreadLock();

	// the makelist and chopbrushes could be cached between the passes...
	brushes = MakeBspBrushList(brush_start, brush_end, mins, maxs);
	if(!brushes){
		node = AllocNode();
		node->plane_num = PLANENUM_LEAF;
		node->contents = CONTENTS_SOLID;
		block_nodes[xblock + 5][yblock + 5] = node;
		ThreadUnlock();
		return;
	}


	if(!nocsg)
		brushes = ChopBrushes(brushes);

	tree = BrushBSP(brushes, mins, maxs);

	ThreadUnlock();
	block_nodes[xblock + 5][yblock + 5] = tree->head_node;
}
Exemple #22
0
/**
 * @brief
 */
static _Bool EndOfScript(_Bool crossline) {
	if (!crossline) {
		Com_Error(ERROR_FATAL, "Line %i is incomplete\n", scriptline);
	}

	if (!g_strcmp0(script->file_name, "memory buffer")) {
		endofscript = true;
		return false;
	}

	Mem_Free(script->buffer);
	if (script == scriptstack + 1) {
		endofscript = true;
		return false;
	}
	script--;
	scriptline = script->line;
	Com_Verbose("returning to %s\n", script->file_name);
	return GetToken(crossline);
}
Exemple #23
0
/*
 * AddScriptToStack
 */
static void AddScriptToStack(const char *file_name){
	int size;

	script++;
	if(script == &scriptstack[MAX_INCLUDES])
		Com_Error(ERR_FATAL, "Script file exceeded MAX_INCLUDES\n");

	strcpy(script->file_name, file_name);

	size = Fs_LoadFile(script->file_name, (void **)(char *)&script->buffer);

	if(size == -1)
		Com_Error(ERR_FATAL, "Could not load %s\n", script->file_name);

	Com_Verbose("Loading %s (%d bytes)\n", script->file_name, size);

	script->line = 1;

	script->script_p = script->buffer;
	script->end_p = script->buffer + size;
}
Exemple #24
0
/*
 * =============
 * SetAreaPortalAreas_r
 *
 * Just decend the tree, and for each node that hasn't had an
 * area set, flood fill out from there
 * =============
 */
static void SetAreaPortalAreas_r(node_t *node) {
    bsp_brush_t *b;
    entity_t *e;

    if (node->plane_num != PLANENUM_LEAF) {
        SetAreaPortalAreas_r(node->children[0]);
        SetAreaPortalAreas_r(node->children[1]);
        return;
    }

    if (node->contents == CONTENTS_AREA_PORTAL) {
        if (node->area)
            return; // already set

        b = node->brushes;
        e = &entities[b->original->entity_num];
        node->area = e->portal_areas[0];
        if (!e->portal_areas[1]) {
            Com_Verbose("WARNING: areaportal entity %i doesn't touch two areas\n",
                        b->original->entity_num);
            return;
        }
    }
}
Exemple #25
0
/*
 * ProcessWorldModel
 */
static void ProcessWorldModel(void){
	entity_t *e;
	tree_t *tree;
	boolean_t leaked;
	boolean_t optimize;

	e = &entities[entity_num];

	brush_start = e->first_brush;
	brush_end = brush_start + e->num_brushes;
	leaked = false;

	// perform per-block operations
	if(block_xh * 1024 > map_maxs[0])
		block_xh = floor(map_maxs[0] / 1024.0);
	if((block_xl + 1) * 1024 < map_mins[0])
		block_xl = floor(map_mins[0] / 1024.0);
	if(block_yh * 1024 > map_maxs[1])
		block_yh = floor(map_maxs[1] / 1024.0);
	if((block_yl + 1) * 1024 < map_mins[1])
		block_yl = floor(map_mins[1] / 1024.0);

	if(block_xl < -4)
		block_xl = -4;
	if(block_yl < -4)
		block_yl = -4;
	if(block_xh > 3)
		block_xh = 3;
	if(block_yh > 3)
		block_yh = 3;

	for(optimize = false; optimize <= true; optimize++){
		Com_Verbose("--------------------------------------------\n");

		RunThreadsOn((block_xh - block_xl + 1) * (block_yh - block_yl + 1),
				!verbose, ProcessBlock_Thread);

		// build the division tree
		// oversizing the blocks guarantees that all the boundaries
		// will also get nodes.

		Com_Verbose("--------------------------------------------\n");

		tree = AllocTree();
		tree->head_node = BlockTree(block_xl - 1, block_yl - 1, block_xh + 1, block_yh + 1);

		tree->mins[0] = (block_xl) * 1024;
		tree->mins[1] = (block_yl) * 1024;
		tree->mins[2] = map_mins[2] - 8;

		tree->maxs[0] = (block_xh + 1) * 1024;
		tree->maxs[1] = (block_yh + 1) * 1024;
		tree->maxs[2] = map_maxs[2] + 8;

		// perform the global operations
		MakeTreePortals(tree);

		if(FloodEntities(tree))
			FillOutside(tree->head_node);
		else {
			leaked = true;
			LeakFile(tree);

			if(leaktest){
				Com_Error(ERR_FATAL, "--- MAP LEAKED, ABORTING LEAKTEST ---\n");
			}
			Com_Verbose("**** leaked ****\n");
		}

		MarkVisibleSides(tree, brush_start, brush_end);
		if(noopt || leaked)
			break;
		if(!optimize){
			FreeTree(tree);
		}
	}

	FloodAreas(tree);
	MakeFaces(tree->head_node);
	FixTjuncs(tree->head_node);

	if(!noprune)
		PruneNodes(tree->head_node);

	WriteBSP(tree->head_node);

	if(!leaked)
		WritePortalFile(tree);

	FreeTree(tree);
}
Exemple #26
0
/**
 * @brief Initialize the OpenGL context, returning true on success, false on failure.
 */
void R_InitContext(void) {
	int32_t w, h;

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

	if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
		if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
			Com_Error(ERROR_FATAL, "%s\n", SDL_GetError());
		}
	}

	uint32_t flags = SDL_WINDOW_OPENGL;

	if (r_allow_high_dpi->integer) {
		flags |= SDL_WINDOW_ALLOW_HIGHDPI;
	}

	if (r_fullscreen->integer) {
		w = Max(0, r_width->integer);
		h = Max(0, r_height->integer);

		if (r_width->integer == 0 && r_height->integer == 0) {
			SDL_DisplayMode best;
			SDL_GetDesktopDisplayMode(0, &best);

			w = best.w;
			h = best.h;
		}
		flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
	} else {
		w = Max(0, r_windowed_width->integer);
		h = Max(0, r_windowed_height->integer);

		flags |= SDL_WINDOW_RESIZABLE;
	}

	Com_Print("  Trying %dx%d..\n", w, h);

	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);

	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	const int32_t s = Clamp(r_multisample->integer, 0, 8);

	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, s ? 1 : 0);
	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, s);

	if ((r_context.window = SDL_CreateWindow(PACKAGE_STRING,
	                        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, flags)) == NULL) {
		Com_Error(ERROR_FATAL, "Failed to set video mode: %s\n", SDL_GetError());
	}

	Com_Print("  Setting up OpenGL context..\n");

	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);

	if ((r_context.context = SDL_GL_CreateContext(r_context.window)) == NULL) {
		Com_Error(ERROR_FATAL, "Failed to create OpenGL context: %s\n", SDL_GetError());
	}

	int32_t attr[SDL_GL_CONTEXT_RELEASE_BEHAVIOR];
	for (int32_t i = 0; i < SDL_GL_CONTEXT_RELEASE_BEHAVIOR; i++) {
		SDL_GL_GetAttribute(i, &attr[i]);
	}

	Com_Verbose("   Buffer Sizes: r %i g %i b %i a %i depth %i stencil %i framebuffer %i\n", attr[SDL_GL_RED_SIZE],
	            attr[SDL_GL_GREEN_SIZE], attr[SDL_GL_BLUE_SIZE], attr[SDL_GL_ALPHA_SIZE], attr[SDL_GL_DEPTH_SIZE],
	            attr[SDL_GL_STENCIL_SIZE], attr[SDL_GL_BUFFER_SIZE]);
	Com_Verbose("   Double-buffered: %s\n", attr[SDL_GL_DOUBLEBUFFER] ? "yes" : "no");
	Com_Verbose("   Multisample: %i buffers, %i samples\n", attr[SDL_GL_MULTISAMPLEBUFFERS],
	            attr[SDL_GL_MULTISAMPLESAMPLES]);
	Com_Verbose("   Version: %i.%i (%i flags, %i profile)\n", attr[SDL_GL_CONTEXT_MAJOR_VERSION],
	            attr[SDL_GL_CONTEXT_MINOR_VERSION], attr[SDL_GL_CONTEXT_FLAGS], attr[SDL_GL_CONTEXT_PROFILE_MASK]);

	if (SDL_GL_SetSwapInterval(r_swap_interval->integer) == -1) {
		Com_Warn("Failed to set swap interval %d: %s\n", r_swap_interval->integer, SDL_GetError());
	}

	if (SDL_SetWindowBrightness(r_context.window, r_gamma->value) == -1) {
		Com_Warn("Failed to set gamma %1.1f: %s\n", r_gamma->value, SDL_GetError());
	}

	int32_t dw, dh;
	SDL_GL_GetDrawableSize(r_context.window, &dw, &dh);

	r_context.render_width = r_context.width = dw;
	r_context.render_height = r_context.height = dh;

	int32_t ww, wh;
	SDL_GetWindowSize(r_context.window, &ww, &wh);

	r_context.window_width = ww;
	r_context.window_height = wh;

	r_context.high_dpi = dw > ww && dh > wh;

	r_context.fullscreen = SDL_GetWindowFlags(r_context.window) & SDL_WINDOW_FULLSCREEN;

	R_SetWindowIcon();
}
Exemple #27
0
/*
 * @brief
 */
static void LoadPortals(const char *filename) {
	uint32_t i;
	portal_t *p;
	leaf_t *l;
	char magic[80];
	char *buffer, *s;
	int32_t len;
	int32_t num_points;
	winding_t *w;
	int32_t leaf_nums[2];
	plane_t plane;

	if (Fs_Load(filename, (void **) &buffer) == -1)
		Com_Error(ERR_FATAL, "Could not open %s\n", filename);

	s = buffer;

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

	if (sscanf(s, "%79s\n%u\n%u\n%n", magic, &map_vis.portal_clusters, &map_vis.num_portals, &len)
			!= 3)
		Com_Error(ERR_FATAL, "Failed to read header: %s\n", filename);
	s += len;

	if (g_strcmp0(magic, PORTALFILE))
		Com_Error(ERR_FATAL, "Not a portal file: %s\n", filename);

	Com_Verbose("Loading %4u portals, %4u clusters from %s...\n", map_vis.num_portals,
			map_vis.portal_clusters, filename);

	// these counts should take advantage of 64 bit systems automatically
	map_vis.leaf_bytes = ((map_vis.portal_clusters + 63) & ~63) >> 3;
	map_vis.leaf_longs = map_vis.leaf_bytes / sizeof(long);

	map_vis.portal_bytes = ((map_vis.num_portals * 2 + 63) & ~63) >> 3;
	map_vis.portal_longs = map_vis.portal_bytes / sizeof(long);

	// each file portal is split into two memory portals
	map_vis.portals = Mem_Malloc(2 * map_vis.num_portals * sizeof(portal_t));

	// allocate the leafs
	map_vis.leafs = Mem_Malloc(map_vis.portal_clusters * sizeof(leaf_t));

	map_vis.uncompressed_size = map_vis.portal_clusters * map_vis.leaf_bytes;
	map_vis.uncompressed = Mem_Malloc(map_vis.uncompressed_size);

	map_vis.base = map_vis.pointer = d_bsp.vis_data;
	d_vis->num_clusters = map_vis.portal_clusters;
	map_vis.pointer = (byte *) &d_vis->bit_offsets[map_vis.portal_clusters];

	map_vis.end = map_vis.base + MAX_BSP_VISIBILITY;

	for (i = 0, p = map_vis.portals; i < map_vis.num_portals; i++) {
		int32_t j;

		if (sscanf(s, "%i %i %i %n", &num_points, &leaf_nums[0], &leaf_nums[1], &len) != 3) {
			Com_Error(ERR_FATAL, "Failed to read portal %i\n", i);
		}
		s += len;

		if (num_points > MAX_POINTS_ON_WINDING) {
			Com_Error(ERR_FATAL, "Portal %i has too many points\n", i);
		}

		if ((uint32_t) leaf_nums[0] > map_vis.portal_clusters || (uint32_t) leaf_nums[1]
				> map_vis.portal_clusters) {
			Com_Error(ERR_FATAL, "Portal %i has invalid leafs\n", i);
		}

		w = p->winding = NewWinding(num_points);
		w->original = true;
		w->num_points = num_points;

		for (j = 0; j < num_points; j++) {
			double v[3];
			int32_t k;

			// scanf into double, then assign to vec_t
			// so we don't care what size vec_t is
			if (sscanf(s, "(%lf %lf %lf ) %n", &v[0], &v[1], &v[2], &len) != 3)
				Com_Error(ERR_FATAL, "Failed to read portal vertex definition %i:%i\n", i, j);
			s += len;

			for (k = 0; k < 3; k++)
				w->points[j][k] = v[k];
		}
		if (sscanf(s, "\n%n", &len)) {
			s += len;
		}

		// calc plane
		PlaneFromWinding(w, &plane);

		// create forward portal
		l = &map_vis.leafs[leaf_nums[0]];
		if (l->num_portals == MAX_PORTALS_ON_LEAF)
			Com_Error(ERR_FATAL, "MAX_PORTALS_ON_LEAF\n");
		l->portals[l->num_portals] = p;
		l->num_portals++;

		p->winding = w;
		VectorSubtract(vec3_origin, plane.normal, p->plane.normal);
		p->plane.dist = -plane.dist;
		p->leaf = leaf_nums[1];
		SetPortalSphere(p);
		p++;

		// create backwards portal
		l = &map_vis.leafs[leaf_nums[1]];
		if (l->num_portals == MAX_PORTALS_ON_LEAF)
			Com_Error(ERR_FATAL, "MAX_PORTALS_ON_LEAF\n");
		l->portals[l->num_portals] = p;
		l->num_portals++;

		p->winding = NewWinding(w->num_points);
		p->winding->num_points = w->num_points;
		for (j = 0; j < w->num_points; j++) {
			VectorCopy(w->points[w->num_points - 1 - j], p->winding->points[j]);
		}

		p->plane = plane;
		p->leaf = leaf_nums[0];
		SetPortalSphere(p);
		p++;
	}

	Fs_Free(buffer);
}
Exemple #28
0
/*
 * @brief
 */
void LoadMapFile(const char *file_name) {
	int32_t subdivide;
	int32_t i;

	Com_Verbose("--- LoadMapFile ---\n");

	LoadScriptFile(file_name);

	memset(map_brushes, 0, sizeof(map_brush_t) * MAX_BSP_BRUSHES);
	num_map_brushes = 0;

	memset(map_brush_sides, 0, sizeof(side_t) * MAX_BSP_SIDES);
	num_map_brush_sides = 0;

	memset(map_brush_textures, 0, sizeof(map_brush_texture_t) * MAX_BSP_SIDES);

	memset(map_planes, 0, sizeof(map_plane_t) * MAX_BSP_PLANES);
	num_map_planes = 0;

	num_entities = 0;
	while (ParseMapEntity()) {
	}

	subdivide = atoi(ValueForKey(&entities[0], "subdivide"));

	if (subdivide >= 256 && subdivide <= 2048) {
		Com_Verbose("Using subdivide %d from worldspawn.\n", subdivide);
		subdivide_size = subdivide;
	}

	ClearBounds(map_mins, map_maxs);
	for (i = 0; i < entities[0].num_brushes; i++) {
		if (map_brushes[i].mins[0] > MAX_WORLD_COORD)
			continue; // no valid points
		AddPointToBounds(map_brushes[i].mins, map_mins, map_maxs);
		AddPointToBounds(map_brushes[i].maxs, map_mins, map_maxs);
	}

	Com_Verbose("%5i brushes\n", num_map_brushes);
	Com_Verbose("%5i clip brushes\n", c_clip_brushes);
	Com_Verbose("%5i total sides\n", num_map_brush_sides);
	Com_Verbose("%5i box bevels\n", c_box_bevels);
	Com_Verbose("%5i edge bevels\n", c_edge_bevels);
	Com_Verbose("%5i entities\n", num_entities);
	Com_Verbose("%5i planes\n", num_map_planes);
	Com_Verbose("%5i area portals\n", c_area_portals);
	Com_Verbose("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]);
}
Exemple #29
0
/*
 * @brief
 */
static void ParseBrush(entity_t *mapent) {
	map_brush_t *b;
	int32_t i, j, k;
	side_t *side, *s2;
	int32_t plane_num;
	map_brush_texture_t td;
	vec3_t planepts[3];

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

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

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

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

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

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

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

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

		// read the texturedef
		GetToken(false);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		return;
	}

	AddBrushBevels(b);

	num_map_brushes++;
	mapent->num_brushes++;
}