Another ARGB bit shifting Q

Blitz3D Forums/Blitz3D Beginners Area/Another ARGB bit shifting Q

Stevie G(Posted 2005) [#1]
In the past I've asked how to use bit shifting to reduce a pixel color by half .. and got this reply .. which works great.

ARGB = ( ARGB And $FEFEFE) Shr 1

What I want to do is only reduce a pixel color to 75% or 80% of it's original color ( a sort of fade )but using a method similar to above. I know I can multiply the rgb components by .75 to do this. For some reason all this shifting left / right is beyond me .. anyone got something which can help?


Who was John Galt?(Posted 2005) [#2]
Bit shifting only divides by powers of 2, so you're out of luck.


sswift(Posted 2005) [#3]
Here is why that works:

Lets say the value of each byte is 255.

Let's also look only at the last two bytes, G and B.

In memory, the bits for G and B would look as follows:

11111111 11111111

Now, the trick you're using first masks each of the bytes with $FE.

$FE looks like this in binary: 11111110

If we then AND (mask) our two bytes with this, we will get 0's wherever our mask is 0.

So for our two 255 values, we get:
11111110 11111110

This is the trick...

Shifting right divides a number. Shifting right by 1 divides it by 2. Shifting right by 2 divides it by 4... 3 divides by 8... etc. Powers of 2.

But if we want to shift all the bytes at once, we don't want the bits from teh green byte overflowing into the blue byte.

For example, if our bytes looked like this:

00000001 00000001

And we shifted right by 1, we would get:

00000000 10000000

Which is wrong, because now green is 0, but blue has become 128!

If we first mask off the bits that will overflow with 0 though, we can divide without worrying about the overflow, because the overflows will be 0 and will not affect the value of the bytes below!


What this means for you is that you can only do this particular trick if you want to divide by 2, 4, 8, etc.

Masking the TWO lowest bits of each byte and dividing by 4 would be equivalent to multiplying by .25.

But there is no equivalent to .75.

I don't think there is any way you could shift the bits that would be faster than masking off the bits and multiplying them individually for such values. Modern processors pretty much multiply as fast as they shift.


Stevie G(Posted 2005) [#4]
Thanks for the explanation. You gave me the answer there add 50% and 25% of the original colour.. Cheers!

RGB1 = ( ReadPixelFast ( x, y ) ) And $FEFEFE) Shr 1
RGB2 = RGB1 Shr 1
Mix = RGB1 + RGB2
writepixelfast x, y, Mix


sswift(Posted 2005) [#5]
Don't you need to mask the second operation too though like the first? Otherwise you might get that overflow.


Stevie G(Posted 2005) [#6]
Looks fine to me :)


Stevie G(Posted 2005) [#7]
In fact I'm start getting strange colours after a while ... I'll try what you say Sean. So I should mark RGB2 as ( RGB1 and $FEFEFE ) shr 1 and then add. Will this work? At work ATM.


sswift(Posted 2005) [#8]
I think it will work, but I'm not positive.


Stevie G(Posted 2005) [#9]
Pah ... it doesn't .... In fact is does for 16bit color depth but just not for 32. Any ideas how I can deal with both?


_PJ_(Posted 2005) [#10]

Thanks for the explanation. You gave me the answer there add 50% and 25% of the original colour.. Cheers!




I thought this as I read through although all this shifting stuff makes my brain hurt!

Thanks for the explanation, Sswift, that was really simple to understand and is good to know.


sswift(Posted 2005) [#11]
Are you saying it works for 16 bit color, but not for 32 bit color?


It should work for 32 bit color. 16 bit color though... I forget if Blitz3D returns colors in a different format when you're reading fro a 16 bit display, but I'm pretty sure it doesn't. I'm pretty sure it converts it to the same format as 32, just with less precision.

I made this test and it appears to work for all numbers:

For Loop = 0 To 255
   
	RGB = Loop + Loop Shl 8 + Loop Shl 16
	Print (RGB And $FF)
   
	RGB1 = (RGB And $FEFEFE) Shr 1
	Print (RGB1 And $FF)

	RGB2 = (RGB1 And $FEFEFE) Shr 1
	Print (RGB2 And $FF)
	
	Print ""
	
	RGB3 = RGB1 + RGB2
	Print (RGB3 And $FF)
	Print Floor((RGB And $FF) * 0.75)
	
	Print ""
	Print ""

Next	
	
WaitKey()