# Wallgroup exercise! (actually wallgroup question :) )

## Recommended Posts

Hi guys!

I need a little help understanding wallgroups and how they are handled by the Infinity Engine. I would like to understand what set of rules the engine uses to determine if a wallgroup is rendered above or below a creature. I'm not sure because there are exceptions that contradict my current hypothesis yet apparently work fine according to DLTCEP tutorial, so something must be wrong with my understanding.

But a picture is better than a thousand words!

Ok, according to my understanding, here's how the engine determines if a creature is drawn in front of or behind an object like this brown block.

1/ The engine takes the polygon made by the level designer and assumes it is the area represented by the block.

2/ The blue line represents the baseline, every creature with its feet above this line is meant to be drawn below the block. If a creature's feet are below the line, draw it in front of the block.

3/ To be more precise, the engine takes the creature's feet X coordinates, and then checks which point of the base line has the same X coordinates. If the corresponding base line point has an Y coordinate higher than the creature's feet Y coord, draw the cre in front of the block. Draw it behind the block if the Y coordinate of the baseline point is lower (i.e. if the point is further down on the screen than cre's feet).

4/ What's the red dot's purpose? I'm not too sure.

My picture applies these rules, but as you can see in case 1, the orange guy is drawn wrong. So okay, maybe I used the wrong baseline? Well then in case 2, green guy definitely has something wrong now.

That means I don't understand correctly how the engine parses the polygons data (i.e. what algorithm, what rules it uses to determine who goes behind what).

Could someone please give me a hand?

PS: I doubt it, but maybe I'm correct and the engine would produce the same results as my picture when given the same polygon and baseline? (meaning I'm correct and have to break the brown block in two wallgroups for it to look good)

I doubt it because this is a plain convex polygon and I read these don't pose any problem provided the right baseline.

##### Link to post

You're almost right and no, you're not going loopy. I don't think any of us fullly understand how the IE figures out what to do with wallgroups because what works (apparently) correctly in one area can then go on to do something completely different in another. Adding overlapping wallgroups (which you'll find is a necessity) can also change the action of an existing wallgroup. The wallgroup flag description table in the DLTCEP area making tutorial can be considered as what will happen for a standalone wallgroup 95% of the time; the other 5% of the time you're at the mercy of the Infinity Engine.

One of the most irritating problems is the standalone rectangular wallgroup that simply doesn't work. There's no apparent reason for the failure but it refuses to dither any part of any sprite that is inside the baseline. The only solution to this one is to throw away the wallgroup and in its place, create a set of smaller wallgroups to cover the same area - and test each one as you create it. If you look at any of the large canon areas you'll find a lot of this.

The red dot is simply the currently-selected vertex.

-Y-

##### Link to post

Thanks for your reply. That's sorta worse news than "you didn't understand a word of what the tutorial told you dude, just get out of here"

Because the only way I'll be able to understand now is by looking at GemRB's source code (which I've already done and not just once) in an attempt to find the algorithm(s) and understand them. Not that the source is badly written or anything, I just always have pain trying to find needles in huge libraries no matter how organized they are ^^

So before I go and dig again, can I safely assume that GemRB MUST have an algorithm of its own to emulate IE's depth sorting, and that this emulated algorithm can deal with wallgroups? I'd say yes but better be safe than sorry (and if someone actually knows where the needle is located, even better! )

Lastly I think it would help me indeed if I could have a look on what the community has already done regarding (for instance) BG2 areas. Isn't there a place where I can see many of these areas with their wallgroups showing? (like this)

Thanksalot!

##### Link to post

Yes, GemRB has a sorting algorithm.

For example: "Map.cpp" line 1959 inserts a projectile into the projectile list based on its height and Y coordinate.

The ordered rendering is done near "Map.cpp" line 1090

If a sprite changes position, the code at "Map.cpp" line 1801 recalculates its 'sprite cover'. That is the wallgroup specific part.

Actually, that's only for area animations that don't really change position (so their sprite cover is calculated only once).

For actors, actor->SetSpriteCover(NULL) forces it to recalculate the cover.

And at "Actor.cpp" line 5122 it generates one.

##### Link to post

Awesome, needles! Jumping in the stack, be back if I understand anything (or nothing)

...About an hour later...

Man, isn't this interesting! There's a whole lot of stuff in there. I learnt a couple more things, but even though you dropped my face right into the needle pot I couldn't extract the set of rules I'm looking for. I know it's there but I can't help it. *bangs head on needles*

##### Link to post

Hehehe, I guess that would be too easy if there was a

```if ( creature.y < wallgroup.getBaselineOrdinate(creature.x) )	{
draw(creature);
draw(wallgroup);
}
else	{
draw(wallgroup);
draw(creature);
}```

##### Link to post

The abovementioned code is actually there, though not for wallgroups, it merges not just 2 lists but 5: actors, area animations, vvc animations, projectiles and sparkles.

Wallgroup cover is calculated once for every potentially covered sprite, when they change position or dimension. It is used to 'cut out' parts from the sprite before rendering it.

##### Link to post

One of your earlier needles, Map::SortQueues, seem to order your 5 actor's baseline according to their ordinate (not wallgroups baseline, I think it's talking about some line under a creature's feet for instance). So I think I see what you're referring to in your first sentence.

____________

Now I take another needle ("Map.cpp" line 1801), Map::BuildSpriteCover, and uhhh, now I'm confused by the C++ syntax. I'm used to higher level languages.

```Video* video = core->GetVideoDriver();
video->InitSpriteCover(sc, flags);

unsigned int wpcount = GetWallCount();
unsigned int i;

for (i = 0; i < wpcount; ++i)
{
Wall_Polygon* wp = GetWallGroup(i);
if (!wp) continue;
if (!wp->PointCovered(x, y)) continue;

}```

Where are InitSpriteCover, PointCovered and AddPolygonToSpriteCover defined? I only see the video ones declared as virtual in Video.h (I don't know where to find what they do), and I see no mention of PointCovered. Wall_Polygon is declared in Map.h as a class but I can't find its PointCovered method.

______________

Finally, Map::BuildSpriteCover seems to be called only from AreaAnimation::Draw:

```	int ac = animcount;
while (ac--) {
Animation *anim = animation[ac];
Sprite2D *frame = anim->NextFrame();
if(covers) {
if(!covers[ac] || !covers[ac]->Covers(Pos.x, Pos.y, frame->XPos, frame->YPos, frame->Width, frame->Height)) {
delete covers[ac];
covers[ac] = area->BuildSpriteCover(Pos.x, Pos.y, -anim->animArea.x,
-anim->animArea.y, anim->animArea.w, anim->animArea.h, 0);
}
}
video->BlitGameSprite( frame, Pos.x + screen.x, Pos.y + screen.y,
BLIT_TINTED, tint, covers?covers[ac]:0, palette, &screen );
}```

What it does is, for each area animation in the area, it checks whether there is a cover. If not or if the cover does not cover the size of the whole animation frame (since its size could change from one frame to the other), the cover is rebuilt.

Right? Now what to do with the cover? Can't find BlitGameSprite's instructions (virtual method again, I'm not used to these).

Wallgroup cover is calculated once for every potentially covered sprite, when they change position or dimension. It is used to 'cut out' parts from the sprite before rendering it.

From what I get so far, cover seems to cover the whole animation frame. I guess I'm wrong, how would that be "parts" to cut out...

So ignoring my reading of the code, would I guess correctly when saying this:

For wallgroups, Z-ordering is based on checking whether a creature's bounding box overlaps with the wallgroup. Then we check which parts of the cre overlaps and store this information as a SpriteCover. And finally what? The fact that both overlaps doesn't tell which to cut off, wallgroup graphics or creature. I'm still stumped on that.

##### Link to post

All video stuff is in SDLVideo, it is the only video implementation.

AddPolygonToSpriteCover adds only polygons that need to be removed (covered).

If a wallgroup doesn't cover the sprite, it isn't added.

##### Link to post

Thanks guys

I've been looking at the source and other solutions too. I think I won't be able to understand how IE and GemRB do things unless I spend unreasonable (and frustrating) hours at this.

BUT! I've found a better solution!

Why bother with crazy wallgroup interactions when you can just use a specially rendered map? BG2 already uses a light maps and stuff after all. I guess hardware limitations prevented BG2 from using yet another map back then...

##### Link to post

A map might be easier than a bunch of oddly-flagged polygons. You might want to check this out - I believe it is an attempt to render a sort of wallgroup map into polygon form that the engine can understand.

##### Link to post

There's interesting stuff in there, thanks

I'll be reading it in order to find ideas that could be adapted for me. At the moment I don't think I need any other map for Z-sorting, but there might be an issue in the way I'm doing things.

Basically entities intersect with each other in a per-pixel way that looks very much like real 3D intersection. But that could pose problems with supposedly solid entities that should not intersect with one another, because there is no way to determine which pixel should not be drawn over another when the Z-buffer says it should.

I don't know how to solve this issue and hope it's possible to just get around it by designing levels correctly. If you have an actual solution though I'm all for it! That'd be great.

#### Archived

This topic is now archived and is closed to further replies.

×
• Website