Avirox's Rotation Tutorial Adapted to NetQuake

Post tutorials on how to do certain tasks within game or engine code here.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

if (!self.spawnflags & 4)
that looks wrong. :S
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

Baker: Using LinkDoors spawns the trigger field in very weird places. After I got really frustrated about it, otp said "Ordnung muß sein?" and Lardarse said something to the effect of, "do it another way". So I did.

There is perhaps a way to check for rotating doors touching via QC, but I didn't see it yesterday (hey, I'm not a coder, I'm a mapper).

Spike: I'm bad with bitwise operators... is it missing brackets?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

QC operators have a slightly different order of precidence from C.
I believe it'll be interpretted as: if ((!spawnflags) & 4)
which is always false.
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

http://www.quaketastic.com/upload/files ... rotate.zip

Example mod with the rotating stuff (info_null method) plugged into a clean progs.dat. RMQ stuff removed or commented out.

Includes a testmap, with map source, rotatetest.bsp. Keys, linked, shootable and toggle doors, and a continuously rotating bmodel.

Includes QC and (FitzSDL/Quakespasm) Engine source; added code is commented. Includes engine executables.

Explanation for mappers: Create a rotate_door and target it at an info_null which marks the center/axis of rotation. Unlike hiprotate, this is all that's needed (meaning it is also an entity / model saver). I hope mods like Quoth will support this, too, because it's clearly better than the Hipnotic method.

I also hope Fitzquake etc. will support this.

TODO: rotate_train.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Nice! :D
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

Patch: START_OPEN and triggered linked rotating doors

http://kneedeepinthedoomed.wordpress.co ... ing-doors/
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

DirectQ already supports this (in the upcoming version anyway) right out of the box. :D
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

Superb. List of supporting engines include Darkplaces, FTE, Proquake, Qrack, DirectQ and RMQ engine then.

RMQ engine can now be gotten from my blog, until hopefully a Quakespasm update obsoletes it? :-)

edit:

http://www.quaketastic.com/upload/files ... patch3.zip

map and progs with acceleration/ deceleration on rotating bmodels
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

OK, a problem has surfaced with very large rotating structures.

I have a pretty big rotate_door, which is part of a moving / rotating bridge. Problem is, the thing starts to "flicker" in non-Darkplaces engines, ie from certain angles, the thing becomes invisible.

AFAIK this happens when the thing is in too many vis leafs? portals? It gets much, much worse in a fullvised map. Probably because there are more vis (leafs/portals/whatever).

However: It doesn't happen in Darkplaces. Yay. So there is a way to fix it. (It also doesn't flicker in AguirRe's enhanced GLquake, but that might stem from the fact that BJPquake doesn't support rotating bmodels. The flickering is in my modified Quakespasm - ie a Fitzquake-derived engine). Couldn't test with newest Proquake, which has rotation support, since it can't load the map. ;-)

I've also tried turning the rotate_door into a func_wall to see if it still flickers. Nope - the func_wall version does NOT flicker, but of course it also doesn't rotate and hence it can probably not be compared directly.

I'm asking someone like mh, LordHavoc, Baker or other engine capable person to give me a hand here. What does darkplaces do differently when it comes to vis culling? And once we find out, can that fix (I suppose it is a sort of fix) be applied to other engines?

I could probably also chop the thing up into a load of smaller rotate_doors, but I'm afraid this will mess up texturing and/or lighting - I'm glad the thing is textured somewhat correctly.

Why does it work in DP with no flickering, even when fullvised?

What to do?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

DP sends bsp ents to all clients regardless of VIS info, last I heard.
So no chance that it can flicker.
Other engines don't quite calculate the absmin/absmax correctly (excessively large), and then drop the ent as it is in half the map (so in too many leafs).
Basically.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Could you upload a progs and a sample map so the problem can be examined first hand?
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

I fixed this in DirectQ a while back, and - if I'm guessing right - you're on the right track with the entity being in too many leafs. Basically what happens is that leafs not in the PVS fill up the allocation of 16 leaf slots that an entity can be in, so it doesn't get sent.

The stock code (SV_WriteEntitiesToClient in sv_main.c, taken from Fitz so it should be relevant to your engine) looks something like:

Code: Select all

			// ignore if not touching a PV leaf
			for (i=0 ; i < ent->num_leafs ; i++)
				if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
					break;
			if (i == ent->num_leafs)
				continue;		// not visible
My replacement looks like:

Code: Select all

			// link to PVS leafs - deferred to here so that we can compare leafs that are touched to the PVS.
			// this is less optimal on one hand as it now needs to be done separately for each client, rather than once
			// only (covering all clients), but more optimal on the other as it only needs to hit one leaf and will
			// start dropping out of the recursion as soon as it does so.  on balance it should be more optimal overall.
			ent->touchleaf = false;
			SV_FindTouchedLeafs (ent, sv.worldmodel->brushhdr->nodes, pvs);

			// if the entity didn't touch any leafs in the pvs don't send it to the client
			if (!ent->touchleaf && !sv_novis.integer)
			{
				//NumCulledEnts++;
				continue;
			}
With my SV_FindTouchedLeafs looking like:

Code: Select all

/*
===============
SV_FindTouchedLeafs

moved to here, deferred find until we hit actual sending to client, and
added test vs client pvs in finding.

note - if directq is being used as a server, this may increase the server processing
===============
*/
void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node, byte *pvs)
{
	mplane_t	*splitplane;
	int			sides;
	int			leafnum;

loc0:;
	// ent already touches a leaf
	if (ent->touchleaf) return;

	// hit solid
	if (node->contents == CONTENTS_SOLID) return;

	// add an efrag if the node is a leaf
	// this is used for sending ents to the client so it needs to stay
	if (node->contents < 0)
	{
loc1:;
		leafnum = ((mleaf_t *) node) - sv.worldmodel->brushhdr->leafs - 1;

		if ((pvs[leafnum >> 3] & (1 << (leafnum & 7))) || sv_novis.integer)
			ent->touchleaf = true;

		return;
	}

	// NODE_MIXED
	splitplane = node->plane;
	sides = BOX_ON_PLANE_SIDE (ent->v.absmin, ent->v.absmax, splitplane);

	// recurse down the contacted sides, start dropping out if we hit anything
	if ((sides & 1) && !ent->touchleaf && node->children[0]->contents != CONTENTS_SOLID)
	{
		if (!(sides & 2) && node->children[0]->contents < 0)
		{
			node = node->children[0];
			goto loc1;
		}
		else if (!(sides & 2))
		{
			node = node->children[0];
			goto loc0;
		}
		else SV_FindTouchedLeafs (ent, node->children[0], pvs);
	}

	if ((sides & 2) && !ent->touchleaf && node->children[1]->contents != CONTENTS_SOLID)
	{
		// test for a leaf and drop out if so, otherwise it's a node so go round again
		node = node->children[1];

		if (node->contents < 0)
			goto loc1;
		else goto loc0;	// SV_FindTouchedLeafs (ent, node, pvs);
	}
}
The old SV_FindTouchedLeafs in world.c (and the call to it in SV_LinkEdict) is then removed from the codebase.

A more quick and dirty solution would be to increase the define of MAX_ENT_LEAFS to something like 32, but you're going to get some extra memory usage overhead from that.
Last edited by mh on Wed Jul 14, 2010 10:33 pm, edited 1 time in total.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

q2 tracks the headnode when it overflows.
though alternatively just set some flag that says 'too many' and just ignore which nodes its in.
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

Right, first off thanks you guys for being so helpful. It's cool knowing you.

This bridge has quietly waited for two years until the day we would finally have proper rotation... now we have, and it's rotating brilliantly (even properly textured, which seems odd and might be coincidence), only to be intercepted by the next problem :-P ah well, that is life.

OK. I tried the quick and dirty way that mh suggested first. I had to raise MAX_ENT_LEAFS to 128 before it worked in the fullvised map. But yeah, that does fix it.

So it can be fixed. I'll try mh's cleaner solution next.

Baker, I'll mail it to you. It's a key section of an RMQ map, so I'd rather not link it atm, but I'll send it to any engine coder who's interested. Makes a good test case I guess.
DP sends bsp ents to all clients regardless of VIS info, last I heard.
That sounds like the cleanest possible solution, but it's probably above my skill level to implement that. I only have a basic understanding of the things involved. Engine coding is only done to get maps running in my case. :-)
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

From memory, halflife raised the limit to 64. The cheats. :P
Post Reply