[help] Passable / Polygon Flags

Posted By: DLively

[help] Passable / Polygon Flags - 07/23/14 03:17

When Changing an entities FLAGS from Passable to Polygon or visa versa, is it neccessary to reset one, then set the other, or can I skip that step?

example:

Code:
reset(me,POLYGON);
set(me,PASSABLE);

...

set(me,POLYGON);
reset(me,PASSABLE);



laugh
Posted By: CyberGhost

Re: [help] Passable / Polygon Flags - 07/23/14 03:31

Of course, you should. An entity can have both PASSABLE and POLYGON set
Posted By: DLively

Re: [help] Passable / Polygon Flags - 07/23/14 03:53

Thanks for the quick response,
But how can it be passable, and use its polygonal hull at the same time?
I thought it was like black and white...
Posted By: Kartoffel

Re: [help] Passable / Polygon Flags - 07/23/14 04:32

I'm quite sure that passable is prioritized.
Posted By: CyberGhost

Re: [help] Passable / Polygon Flags - 07/23/14 07:22

The manual says if PASSABLE is set, the collision is 'switched off'. If so, why is there IGNORE_PASSABLE in the mode for c_ functions? We don't need one that way.
Posted By: DLively

Re: [help] Passable / Polygon Flags - 07/23/14 07:47

because you are instructing the engine to ignore anything with a passable flag enabled.

Quote:

I'm quite sure that passable is prioritized.


Thanks Kartoffel!
You are correct!

Furthermore, After some debugging Setting Passable, and not reseting polygon, will overwrite polygon, and enable passable. However Passable must be reset, before setting polygon again otherwise passable is still enabled, and does take priority.
Posted By: CyberGhost

Re: [help] Passable / Polygon Flags - 07/23/14 07:56

it will ignore it anyway, the collision is switched off

http://manual.conitec.net/aentity-passable.htm
Posted By: Ch40zzC0d3r

Re: [help] Passable / Polygon Flags - 07/23/14 12:51

c_trace will also trace passable models if you dont set the flag...
Posted By: WretchedSid

Re: [help] Passable / Polygon Flags - 07/23/14 14:10

What no one is telling DLively, but probably should, is that the flags are just a bitfield.

Here, let me play Erklärbär once more (explaining bear... But the joke is lost in translation, so we won't talk about that).

A variable, no matter what type (aka, not to be confused with var), occupies a certain number of bits in memory. An int and a var for example occupy 32 bits, or 4 byte, whereas a double for example occupies 8 bytes. This in and off itself isn't that surprising, information has to be stored somewhere and computer use bits and bytes for that, news at 11.

What's more interesting is that you can change the bits. One way, you are already aware of, simply assigning values to it. Like the following:

Code:
int foo = 1234;
foo = 4321;



There is another way though, and that is manipulating the bits directly. You may or may not have seen the bitwise operators already, there is bitwise OR "|" and bitwise AND "&", not to be confused with their boolean counterparts "||" and "&&", there are also two more operators which I will come to in a second.

Bitwise OR takes two bit patterns and sets the output bit pattern in such a way that if either or both bits are 1, the result is 1, otherwise it's 0. Or, put differently and as a picture:
Code:
0100
1101

Both ORed together is
1101



Bitwise AND sets the resulting bit to 1 if both bits are set, example:
Code:
0100
1101

Both AND together is
0100



Now, let's look at how decimal values are actually represented in an integer. Let's stick with 4 bits, because I'm lazy and hate typing, there is no 4 bit integer in C, but screw it, we now have one!
All bits to 0 is 0 in decimal. Then, for every +1, the least significant bit is increased by one (least significant is the one on the rightmost place on x86), because a bit can either hold 0 or 1, adding 1 to a bit that is already 1 causes it to overflow to the left, and become 0. Let's count!

Code:
0000 // -> 0
0001 // -> 1
0010 // -> 2 (Note how the least significant bit spilled over to the left)
0011 // -> 3
0100 // -> 4
0101 // -> 5
0111 // -> 6
1000 // -> 7
1001 // -> 8
1010 // -> 9
1011 // -> 10
1100 // -> 11
1101 // -> 12
1110 // -> 13
1111 // -> 14
0000 // -> 0



Notice the last entry? This is why variables wrap around, they simply overflow and go back to 0.

Of course, a 4 bit integer is now fun because it has only 15 possible states, but adding just 28 more bits to make it a full blown 4byte integer, and suddenly it has 4 billion something possible states!

Okay, now we have almost everything in place to get to entity flags. Lets cover bit shifts real quick! There are two operators to shift bits to the left and to the right, they are << and >> respectively. 1 << 2 would shift the number 1 (0001) by 2 places to the left (01000).

And now, to the flags!
The flags are to be treated as a bitfield. They are a 4 byte integer, but you shouldn't treat it as such but as a bitfield instead. Ie, don't do normal integer mathematic on it(*).

The set and reset "functions" are actually just macros over the & and | bitwise operators, and they look like this:

Code:
#define set(entity, flag) entity->flags |= flag
#define reset(entity, flag) entity->flags &= ~flag



There is nothing fancy, there is no function executed or anything. It just changes bits in the bitfield. Bitfields are perfect for when you have a lot of true/false on/off states to represent, because then you don't waste memory on them. A 32 bit integer, can hold... 32 on/off states, and you toggle them individually via bitwise operators.

What the engine does is the following, whenever it executes code dependend on one of the flags, it checks if the flag is set or not using the AND operator, and then decides how to act accordingly. Pseudo code time!

Code:
void c_move(ENTITY *entity)
{
   if(entiy->flags & PASSABLE)
      return; // Screw it, we are done!

   if(entity->flags & POLYGON)
   {
      // Polygon correct check here
   }
   else
   {
     // Cheap check here
   }
}



Okay, so, last bit of wrap up!
The reset macro, you will notice the tilde in there! That's the third bitwise operator, it's bitwise NOT. It inverts the bit field. Example:
Code:
0100
1011



The flags themselves are also just macros, they look like this, except that I pulled the actual shift values out of my ass:
Code:
#define PASSABLE (1 << 0)
#define POLYGON (1 << 2)



And now for the grand finale and why things like if(flag & XYZ) actually works. Let's visualize you setting the and resetting the PASSABLE and POLYGON flags! I'll use my trusty 4bit integer because it has enough precision:

Code:
// Assume flags has the PASSABLE flag set
flags = 0001

// Now you set the POLYGON flag using flags |= POLYGON
flags = 0001 | 0100
flags = 0101

// Now you reset the PASSABLE flag
inverted = ~0001
inverted = 1110

flags = 0101 & 1110
flags = 0100



See how it works? Now, let's check if the passable flag is set!

Code:
result = 0100 & 0001
result = 0000



0 evaluates to false, so if(flags & PASSABLE) is false. But lets check the POLYGON flag!
Code:
result = 0100 & 0100
result = 0100



Everything greater 0 evaluates to true, so if(flags & POLYGON) is true!

Tada, bitwise operators and bitfields ladies and gentlemen. Useful as fuck!

Now, extra round! There is one last bitwise operator, and that is XOR, or "^". It stands for exclusive OR, and is opposed to OR which is an inclusive OR. Two patterns XORed with each other will result in a bit to be 1 if either of the bits is 1, otherwise its 0. Example:

Code:
0101 ^
1011

1110



Oh boy. Lets toggle some bits with it!
Code:
flags = PASSABLE | POLYGON
flags = 0101

flags ^= PASSABLE
flags = 0101 ^ 0001
flags = 0100

flags ^= PASSABLE
flags = 0100 ^ 0001
flags = 0101



The logical conclusion I'm trying to get at for so long already is, that it doesn't matter in which order you use set() and reset(). You just change some bits around, and the order doesn't matter, there is no engine function executed or anything which alters the result, the flags are evaluated on demand by the engine.

Now, you can do much more stuff with the operators, for example read out only certain bit ranges of an integer. But this is for another day.


(*) Technically, because single bits always represent a power of two, you can use the + and - arithmetic operators. For example, the following works as well:
Code:
flags = PASSABLE + POLYGON



However, it's not done because then it stops being clear wether or not you are working with a bitfield or a normal variable.
Posted By: DLively

Re: [help] Passable / Polygon Flags - 07/23/14 15:58

confused confused confused

This will take several readings before I finally understand it in its entirety, although it seems pretty straight forward if that makes any sense confused .

Once again, JustSid - You've blown my mind! I dont have much time at the moment to re-read it to make sense of it now, however when all my chores and tasks for the day are complete, I will come and read this over once more, and probably again another time.

I have read into Bits and Bytes, and how they work (unless that was another post by you grin ) before and so I have a foundation for what you are trying to teach me, I just need more time to try and understand it further.

As always, a wonderful Lesson. I really appreciate your help Bro! Thank goodness we have you in the community!

Truly Confused,
DLively.
Posted By: CyberGhost

Re: [help] Passable / Polygon Flags - 07/23/14 19:15

Oh ,man! Now I understood! I was just seeing the defines for the flags and was like 'WTF? WHAT IS > ? What is...etc.'

Btw. what is 'obj->' ? I mean what is -> ?
Posted By: Kartoffel

Re: [help] Passable / Polygon Flags - 07/23/14 19:16

afaik it's just like '.'

you.x
you->x
Posted By: lemming

Re: [help] Passable / Polygon Flags - 07/23/14 20:06

You use obj->x when obj is a pointer.

So like:
Code:
typedef struct mystruct {
  var val1;
  var val2;
} mystruct;

mystruct obj1;
mystruct* obj2 = sys_malloc(sizeof(mystruct));

obj1.val1 = 10;
obj2->val1 = 20;   // << Because obj2 is a pointer you use the arrow



LiteC does an automatic ->/. conversion. It's nice at the beginning but will screw everything when you advance.
Posted By: WretchedSid

Re: [help] Passable / Polygon Flags - 07/23/14 21:11

Yes, -> and . are both for member access, and . is for objects and -> is for pointers.

That doesn't explain why that is there though. Kids, gather around!

The reason we have this confusing stuff and carry it around to this day is because of bearded guy called Dennis Ritchie. He wrote the C Reference Manual. And is the father of C. And UNIX. And he did other stuff as well.

What Dennis Ritchie made and called C is far away form what we call C nowadays (and thank god for that). The C Reference Manual, CRM, had quirky definition for structs and their members, like seriously quirky. A struct member defined a global offset for the translation unit it occurred in, for example, take the following struct;

Code:
struct foo
{
   int a;
   int b;
   int c;
};



c would afterwards be a globally defined offset of 8, because it was at the 8th byte offset of the struct foo. Similar, a would have a defined offset of 0. And now you could do fun things like this:

Code:
int x;
x.b = 24;



It did exactly what no sane person would expect it to do: Write 24 at offset 4 of the integer x. So _after_ the integer.

Only issue, it didn't work with addresses, so it didn't work on pointers. Dereferencing the pointer first didn't work either, because the reason it doesn't work with pointers is also the reason the expression (*bar) was illegal because it simply requires an lvalue operand.

The solution was the -> operator, which didn't care if it was an lvalue or an rvalue, treated everything as an address, applied the offset, dereferenced it and then wrote the value you wanted into it. Example:
Code:
1024->b = 5; // Writes 5 to address 1028

int x = 4;
x->c = 42; // Writes 42 into 12



Yes, that doesn't make any sense. But, remember, b and c were globally defined offsets, and -> treated everything as address.

And because that's batshit insane, when Ken Thompson joined Dennis and they both made K&R C, they threw away this nonsense altogether. Under K&R C, this global offset stuff was gone, and the -> operator became equivalent to (*x).foo

And that's why both are still there, the -> operator also dereferences the pointer, in addition to what the . operator does. And that's why Ken Thompson got mad pussy and Dennis Ritchie is known as that bearded guy who wrote the CRM.
Posted By: CyberGhost

Re: [help] Passable / Polygon Flags - 07/23/14 23:20

Ok, thanks.
© 2024 lite-C Forums