Skip to main content
gamedev.net
🔒 Locked

Question 13 - operator

Started by joethems1 Jul 26, 2007 at 2:23 PM 2 replies 1.3k views
Original Post
joethems1
joethems1
I want to thank everyone here for the great workshop. I have learned so much already! Here is my first question so far. From Page 71 - The ~ is the bitwise complement operator and is defined only for int, uint, long and ulong. The operator results in a integer of the same type in which all the bits have been flipped from 0 to 1 and from 1 - 0. What is a bitwise complement? I think I understand if I have an int and use the ~ operator that it will take the int and switch its binary representation from 0 to 1 and from 1 to 0 for each bit. Maybe I am missing the underlying knowledge of binary because I have no clue why I would use this and the result I would get form using it? Are there any examples that may enlighten me or a good tutorial on binary so I can further understand bit flipping and switching? An earlier post said shifting isn't really needed any longer, is this also true for flipping? Thanks for your time.
SiCrane
SiCrane
You seem to understand what ~ does properly. As for why you would use it, here's an example the project I'm working on now. In this program I call Sprite.Begin(). Its arguments are a bunch of flags or'd together. The flags I use are:
DoNotSaveState         = (1 << 0); // 0x0001 or 00000001 in binaryDoNotModifyRenderState = (1 << 1); // 0x0002 or 00000010 in binaryAlphaBlend             = (1 << 4); // 0x0010 or 00010000 in binary

So I have a constant in my code
static const int SPRITE_BEGIN_FLAGS = AlphaBlend             |                                      DoNotModifyRenderState |                                      DoNotSaveState;

Which is 0x0013 or 00010011 in binary.

In one place I want to call Sprite.Begin() with all the flags set except for DoNotModifyRenderState, but I don't want to manually type in the flags that I use otherwise. So in that one place instead of Begin(SPRITE_BEGIN_FLAGS), I have: Begin(SPRITE_BEGIN_FLAGS & ~DoNotModifyRenderState). What this does is flips all the bits on DoNotModifyRenderState to 11111101, then and's it with SPRITE_BEGIN_FLAGS for 00010011 & 11111101 = 00010001, which is all the flags I use except for DoNotModifyRenderState. If I later add or remove flags to SPRITE_BEGIN_FLAGS, it will still give me everything in SPRITE_BEGIN_FLAGS except for DoNotModifyRenderState.

A search for "bit tricks" should show you other things you can do with binary operations. (Though not necessarily things you should do.)
joethems1
joethems1
Thank you for the help!

So a good use for the bitwise operators would be when you want to set flags?
Would you use bitwise operators on any other occasion? Comparisons?
From what I have read it looks like these were good methods when memory was a large concern. It was faster to multiply, divide etc using bits and took less space.

I just want to be sure I understand your code:

DoNotSaveState = (1 << 0); // 0x0001 or 00000001 in binary

DoNotModifyRenderState = (1 << 1); // 0x0002 or 00000010 in binary

AlphaBlend = (1 << 4); // 0x0010 or 00010000 in binary


Here you are setting up an enumeration or data structure that defines binary numbers for the above variables. This could be a stupid question but are these values initialized as bytes or as integers? You are using the bit shifting operator to change the value and then assigning it to the variables. Is it ok to declare the above variables like:

DoNotSaveState = 1;
DoNotModifyRenderState = 2;
AlphaBlend = 4;



static const int SPRITE_BEGIN_FLAGS = AlphaBlend |

DoNotModifyRenderState |

DoNotSaveState;

Here you create a constant that defines SPRITE_BEGIN_FLAGS creating a binary number of 00010011. Which means when this constant is passed to your begin method that all the above flags will be "turned on".

Begin(SPRITE_BEGIN_FLAGS & ~DoNotModifyRenderState)

When you call this method and use ~DoNotModifyRenderState you are in effect saying turn everything on except DoNotModifyRenderState.

I think I am a little lost on how binary numbers are handled. Are they implicitly converted(would that be the right term?) if I tried a bitwise operator on an integer?

Thanks again for your help!
SiCrane
SiCrane
Ok, a little more context. This is DirectX code; for C#, the flags are defined in Microsoft.DirectX.Direct3D.SpriteFlags. If you go to the MSDN page for the SpriteFlags enumeration, you'll see a table with the values. It goes something like:
AlphaBlend            16SortDepthBackToFront 128SortDepthFrontToBack  64SortTexture           32Billboard              8 ObjectSpace            4DoNotModifyRenderState 2DoNotSaveState         1  

So the flags in the MSDN documentation are labeled with the decimal value. If you go to the C++ header file for the same function you'll see code like:
#define D3DXSPRITE_DONOTSAVESTATE               (1 << 0)#define D3DXSPRITE_DONOTMODIFY_RENDERSTATE      (1 << 1)#define D3DXSPRITE_OBJECTSPACE                  (1 << 2)#define D3DXSPRITE_BILLBOARD                    (1 << 3)#define D3DXSPRITE_ALPHABLEND                   (1 << 4)#define D3DXSPRITE_SORT_TEXTURE                 (1 << 5)#define D3DXSPRITE_SORT_DEPTH_FRONTTOBACK       (1 << 6)#define D3DXSPRITE_SORT_DEPTH_BACKTOFRONT       (1 << 7)#define D3DXSPRITE_DO_NOT_ADDREF_TEXTURE        (1 << 8)

It's the same thing, just expressed in two different ways. (Though I have no idea why they organized the SpriteFlags table like that. It's neither in alphabetic order nor is it in numeric order. It's just weird.)

Integers in C# (and in computers in general) are in binary. When the computer is dealing with numbers it doesn't see 5, 102 or 5006; it sees 0101, 0110 0110 and 0001 0011 1000 1110. It doesn't need to convert them to binary to use the bitwise operators because they are in binary already.

I, personally, rarely use bitwise operators outside of flags. In fact, in C# I think that's the only way I've ever used them. But still, they can be used in a variety of situations.

One example: DirectX has a type D3DCOLOR used in C/C++; it's actually just a fancy name for an integer that contains the color components mashed together. The top 8 bits are used for the alpha component, the next 8 for the red, then the green and finally the blue. Each color component goes from 0 to 255. So if you wanted a color that was 255 alpha (completely opaque), 255 red, 128 green and 128 blue (sort of a bright pink) you could assemble that as (255 << 24) + (255 << 16) + (128 << 8) + 128. There are helper macros (basically dumbed down functions) to deal with this, but that's what the macros do internally.

Similarly, if you wanted to get the red component of a given D3DCOLOR, call it Fred, you could do: (Fred & 0x00ff0000) >> 16. Or equivalently, (Fred >> 16) & 0xff.

In C# I don't do any of this since the Color structure has A, R, G and B properties that let me get at the color components for a given color and the FromArgb() method to create a Color from given color components. Though internally, they probably do all the same bit manipulations.

Another use: probably the fastest way to determine if a number is a power of 2 is to bitwise and it against itself minus 1 (n & (n - 1)). Though if you do that, stick a comment that says "Testing for power of 2".

Again, if you do a web search for "bit tricks" you can get other examples. Most of which you should never use in real code, but examples nonetheless.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.