Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » getr() & makecol()

This thread is locked; no one can reply to it. rss feed Print
getr() & makecol()
Derezo
Member #1,666
April 2001
avatar

I'm wondering on how getr(), getb(), etc. work..

What I'm trying to do, is store 4 values inside of one long integer - like makecol() does. The values are going to be width, height, x and y values.. I was thinking of just using makecol() as a way to do it.. but.. I don't know what excess stuff goes on in makecol() and getr(), etc. and don't want it to cause slow down.. because my engine is slow enough :P

Anyhoo, thanks.

"He who controls the stuffing controls the Universe"

DanielH
Member #934
January 2001
avatar

Well if that is how you want to do it then you need to learn some shifting. I don't know how it would be better to do it.
You can shift bits
<< up
>> down
// left shift <<
int i=5;-------- //binary 101
print i<<2 ----- //equivalent to i*(2^2)
output: 20 ----- //binary 10100 <--notice it shifted two spots
// right shift >>
int i=5;-------- //binary 101
print i>>2 ----- //equivalent to i/(2^2)
output: 1 ------ //binary 1
--------------------------
makecol 24bits
111111111111111111111111 // 24 bits
the first eight are used by red -
red_mask=111111110000000000000000 //binary
the middle eight are used by green -
green_mask=000000001111111100000000 //binary
the last eight are used by blue -
blue_mask=000000000000000011111111
to get the value we & and shift.
To get the red or green values then we need to shift all eight values to the front. since blue is at the front, no shifting is required.
red =(color & red_mask)>>16
green=(color & green_mask)>>8
blue =(color & blue_mask)

example:
color=101010001010101111110111
color & red_mask
color ---- 101010001010101111110111
red_mask - 111111110000000000000000
-----------------------------------
result --- 101010000000000000000000
red = result>>16 = 10101000 = 168
color & green_mask
color ----- 101010001010101111110111
green_mask- 000000001111111100000000
------------------------------------
result ---- 000000001010101100000000
green = result>>8 = 10101011 = 171
color & blue_mask
color ---- 101010001010101111110111
blue_mask- 000000000000000011111111
-----------------------------------
result --- 000000000000000011110111
green = result = 11110111 = 247
color = 101010001010101111110111 = 168,171,247
------------------------------------
So for your variable, you need to design just exactly what bits do what. Find out the maximum value to determine that amount of bits required.
lets say that your max width and height are 800x600
800 will require 10 bits
600 is also require 10 bits
so far we already using 20 bits
so the first 10 could be the width
width_mask=11111111110000000000=
height_mask=00000000001111111111

int make_val(width,height)
{
return height+width<<10;
}
int get_width(int p)
{
return (p & width_mask)>>10;
}
int get_height(int p)
{
return (p & height_mask);
}

If you want one variable to house x,y,width,height than your variable will need 40bits. You could do it. int is only 32 bits. use long. long has 64 bits.
first 10 for width
second 10 for height
third 10 for x
fourth 10 for y
[ October 28, 2001: Message edited by: DanielH ]

Derezo
Member #1,666
April 2001
avatar

Wow, I understand now..
.....but I'm sorta bad with my binary :P
I definately see how to do it though, thanks a lot.. I always wondered what exactly 'shifting' was.

"He who controls the stuffing controls the Universe"

DanielH
Member #934
January 2001
avatar

binary isn't that hard to understand. Its just a bunch of 1's and 0'
the decimal value is just the sum of each bit multiplied time 2^(place of bit)
binary 1010 = 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0 = 8+0+2+0 = 10
----------------------------
If you did decide to do it this way then your value would be determined as follows
//your masks
w 1111111111000000000000000000000000000000
h 0000000000111111111100000000000000000000
x 0000000000000000000011111111110000000000
y 0000000000000000000000000000001111111111
long get_value(int w,int h,int x,int y)
{
return y+x<<10+h<<20+w<<30;
}
Just make sure the values don't exceed 2^10 which is 1024.
[ October 28, 2001: Message edited by: DanielH ]

Bob
Free Market Evangelist
September 2000
avatar

quote:
long get_value(int w,int h,int x,int y)
{
return y+x<<10+h<<20+w<<30;
}

This leaves 2 bits for the width? And also, the operator precedence is wrong. The code should really be:
code:
long get_value(int w,int h,int x,int y)
{
return y + (x << 8) + (h << 16) + (w << 24);
}

This leaves 8 bits for each quantity, so the range is 0-255 for each. Supporting negative numbers will require a bit more work though.

--
- Bob
[ -- All my signature links are 404 -- ]

Derezo
Member #1,666
April 2001
avatar

The problem I have with binary, is that I can't compute it quickly..
I work from right to left, and I think of it like this..
start at 1, and keep doubling..
1,2,4,8,16,32,64,128.....
changing 0010 to 2 is easy, but changing 10101011 to 171 takes a second.
Anyhoo..
One think I got very confused with when testing...........
I'm confused on the mask, and the '&' operator.. when extracting each value.
w = (value & width_mask)>>10;
The '&' operator is the 'bitwise AND' right?
Well, I don't know EXACTLY what that is :P
I hate to ask you guys to teach me parts of C, but I learned from example.. cuz I'm poor What does the '&' operator do?
Anyhoo, the last thing that got me confused was how exactly the masks should be used.
int height_mask=00000000001111111111;
DJGPP tells me it's too big, and there's gonna be some sort of overflow problem..
whereas if I store it as '1024', it's decimal equivalent, the values end up incorrect.
At first I thought the masks were just a visual aid :P Then again, remember, this probably relates to my lack of knowledge of the '&' operator :P
Thanks, this is helping me understand bit shifting.

"He who controls the stuffing controls the Universe"

Derezo
Member #1,666
April 2001
avatar

Bob:
I think you're mistaking for 32 bit integers, instead of 64 bit long integers..
whereas 'return y+(x<<10)+(h<<20)+(w<<30);' would leave something like...32 bits left for width, and 10 for each other one..
Width, height, x and y.. would contain values as high as 640.. so 8 bits aren't quite enough.
[ October 28, 2001: Message edited by: Derezo ]

"He who controls the stuffing controls the Universe"

Bob
Free Market Evangelist
September 2000
avatar

Under I32LP32 compilers (all of them for the x86, save for the special AMD one), long is 32 bits wide. long long (or int64_t or __int64) is 64 bits wide.

--
- Bob
[ -- All my signature links are 404 -- ]

DanielH
Member #934
January 2001
avatar

Bob: Never actually did that before so didn't know the operator precedence.
I got those values from msdn, I was looking at java. in java a long is 64 bits. Here are the bits in c++
Type Size
char, unsigned char, signed char 1 byte 8 bits
short, unsigned short 2 bytes 16 bits
int, unsigned int 4 bytes 32 bits
long, unsigned long 4 bytes 32 bits
float, 4 bytes 32 bits
double, 8 bytes 64 bits
long double, 8 bytes 64 bits
-----------------------------------------
Probably the best was to represent your masks is to put the value in hex value base 16 where each value is 4 bits
hex 0xF ==== dec 15 ==== bin 1111
hex 0xFF === dec 255 === bin 11111111
hex 0xFFF == dec 4095 == bin 111111111111
hex 0xFFFF = dec 65535 = bin 1111111111111111
---------------------------------
bits
y 0-10
x 11-20
h 21-30
w 31-40
#define Y_MASK 0x3FF
#define X_MASK 0xFFC00
#define H_MASK 0x3FF00000
#define W_MASK 0xFFC0000000
You do have 24 bits remaining to use as you wish. You could split the 64 bits evenly and use 16 bits a piece, but the values could be from 0-65536. Might be a little excessive.
------------------------------------
Or the decimal value could be used.
2^bits -2^(previous)

2^10 ===== 1024=10000000000 // incorrect
2^10-2^0 = 1023=01111111111 // correct
for 10 bits the value would be
[2^10-2^0] == 1023 ========== 1111111111
[2^20-2^10] = 1048576 ======= 11111111110000000000
[2^30-2^20] = 1072693248 ==== 111111111100000000000000000000
[2^40-2^30] = 1098437885952 = 1111111111000000000000000000000000000000
-------------------------------------------
bit operations are AND,OR,XOR and are done on each bit.
AND = & ,is 1 if both bits are 1
OR =
(the character above the \ I'll use : in the post), is 1 if either bit is 1
XOR ^ , is 1 if either bit is 1, but not both bits
-ANDING--,--ORING--,--XORING-
1 & 1 = 1 , 1 : 1 = 1 , 1 ^ 1 = 0
0 & 1 = 0 , 1 : 0 = 1 , 0 ^ 1 = 1
1 & 0 = 0 , 0 : 1 = 1 , 1 ^ 0 = 1
0 & 0 = 0 , 0 : 0 = 0 , 0 ^ 0 = 0
101 & 111 = 101
101 : 111 = 111
101 ^ 111 = 010
------------------------------------------
For negative numbers, we would need an extra bit for each value.
0 would be positive
1 would be negative.
If you send a negative parameter, don't forget to save the neg/pos bit and then shift the absolute value of the number. If you don't and shift a negative number then you will have problems.
I don't really want to get into complements and such.
[ October 29, 2001: Message edited by: DanielH ]

Bob
Free Market Evangelist
September 2000
avatar

quote:char, unsigned char, signed char 1 byte 8 bits
short, unsigned short 2 bytes 16 bits
int, unsigned int 4 bytes 32 bits
long, unsigned long 4 bytes 32 bits
float, 4 bytes 32 bits
double, 8 bytes 64 bits
long double, 8 bytes 64 bits
That's not quite right either.
In C/C++:
char is at least 1 byte.
short is the shortest type the machine can use, that is larger than char.
int is the size of general purpose registers in the machine.
long is the longest type the machine can handle.
As you can see, these are very loose definitions. If you need really precise bit counts, then #include <types.h> and use
int8_t, int16_t, int32_t, int64_t, and so on, which are garenteed to be at least as large as the number of bits they say they have (that can be larger if the machine doesn't support them).
float and double are the only standard ones (IEEE-754). long double is an extension of double, and isn't quite standard. It is 80-bits on the x86, but may not have to be.

--
- Bob
[ -- All my signature links are 404 -- ]

DanielH
Member #934
January 2001
avatar

I have "Teach yourself C++ in 21 days" and it has a program to find out the computer/compiler byts amounts for variables.
print --> sizeof(int)
Did that and got these results (in bytes, 1 byte = 8 bits)
bool 1
char 1
unsigned char 1
short 2
unsigned short 2
int 4
unsigned int 4
long 4
double 8
float 4
fixed 4
long long 8
computer is a Hewlett Packard PIII
I ran this on msvc,ming, and djgpp.
My msvc compiler didn't recognize long long.
------------------------------------
Derezo, If you only access those variables once or twice than this would be ok to do it this way.
But if you need to constantly during your game update,change, retreive those amounts then I would just forget the whole idea and use seperate variables. You would lose too much time in operations.
[ October 29, 2001: Message edited by: DanielH ]

Bob
Free Market Evangelist
September 2000
avatar

DanielH: I have K&R C - the One True C reference.
Install TurboC on your computer and run your sizeof() program. Now do it under a compiler for your microwave oven's CPU.
Some machines don't support unsigned numbers at all. Some machines don't support signed numbers at all. Some machines have only 8 bit registers. Some machines have only 64 bit registers.
C/C++ != Java.
C does NOT have standard type sizes. End of story.

--
- Bob
[ -- All my signature links are 404 -- ]

Derezo
Member #1,666
April 2001
avatar

I think that in the end, this way will be easier. Of course, I gotta go through learning how to do it.. but it will be easier to have 1 array, than 4 arrays of the same size..

It's going to be used with buttons and menus. I think it's a good way to do it when I compare it to how I did it previously.. with 4 different arrays :P

Thanks a LOT for showing me how to do this guys.

"He who controls the stuffing controls the Universe"

Gabhonga
Member #1,247
February 2001
avatar

yeah, in case of computer programming you must make binary (and hex...) math/magic your friend...it can help out a lot in simplifying things.
by the way, you can input binary masks/numbers directly like hex and dec numbers, but with a "b" at the end!!
1100 = 0x44c = 10001001100b
0x1100 = 4352 = 10001...00b (too big to write out now)
1100b = 0xc = 12
so a mask for the first (lower) 8 bits would be:
11111111b or 0xff or 255 (>char, unsigned char) or -1 (signed char)...lot's of stuff to watch, but make dj delories hcalc your friend and after a while you'll even be able to make those calculations in the head(and that's what hex is for, binary is just too many digits to remember/have an overview, so learn at least how to convert binary numbers from 0..15 (a nibble) into hex (0..f) and you don't even need a calculator anymore)
however watch about your packed structs, because intel world is little endian, thus affecting the order bytes are stored in memory: just imagine they're mirrored.
for example the 32 bit int 0xaabbccdd
would be stored in memory(wich is counted in bytes=chars) like this:
offset value
0 dd
1 cc
2 bb
3 aa
if you read the whole int at once from memory, you wont notice, but if you try to read the 4 single chars or 2 shorts it consits of, be prepared to break your head and pay attention to this sceme, otherwise you encounter strange results (values swapped).

--------------------------------------------------------
sigs suck

DanielH
Member #934
January 2001
avatar

Bob- You didn't seem to understand what I was saying. I totally agree with you. You said that machines are different and I was just saying you could find out the sizeof the variables for your machine.
quote:
char is at least 1 byte.
short is the shortest type the machine can use, that is larger than char.
int is the size of general purpose registers in the machine.
long is the longest type the machine can handle.

Wouldn't this work? I didn't say it would be the same for all machines. I'm talking about that machine and not any other.
And I know that java is not C++.
I said I was looking at the wrong table.
Jeez!
Next time I pull my microwave apart, I'll run that code and check also.
--------------------------------
And one other thing. If you masks are the same size bits than you could make one mask and instead of masking then shifting, shift then mask.

Peter Hull
Member #1,136
March 2001

I think the C standard says something unhelpful like short is not longer than int, and int is not longer than long.

My microwave was a Microsoft one; it crashed when I put more than one thing at once in it. :)

To be somewhat more useful - in these days it's not usual to be so short of memory that you have to resort to such tricks. One thing that C provides is a bitfield data type. I've never used it but it could be the thing you're after.

Pete

Bob
Free Market Evangelist
September 2000
avatar

DanielH: ah, well my appolgies then.

--
- Bob
[ -- All my signature links are 404 -- ]

23yrold3yrold
Member #1,134
March 2001
avatar

If you're using limits.h and C++, you can get the maximum values of the different types on different systems. The ones DanielH posted are all the minimum sizes of those types except int, which is 2 bytes or greater depending on the system. Say, you can get the maximum value of an int like this:
code:
#include <limits>
#include <iostream>

int main()
{
cout << numeric_limits<int>::max();
}
Untested, but should work. I don't use limits.h much so I'm not sure.
I don't think this really has anything to do with what's actually being discussed, I just figured I'd throw it out there

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Go to: