UnderwareDESIGN

PlayBASIC => Resources => Source Codes => Topic started by: kevin on July 07, 2010, 04:52:29 PM

Title: Calculate RGB mask for different image depths
Post by: kevin on July 07, 2010, 04:52:29 PM
  This function bellow will calculate the BIT MASK for whatever surface (screen or image) depth you provide it.  This is useful when we're designing our games to run in 32bit display depth, regardless of what the players computer can actually display.   By default the PB graphics library will automatically step down the display depth to whatever the gamers system is using when were running our game in  window modes, or if video card doesn't support the depth in full screen modes.     While unlikely on modern systems, this can occur when running our programs on older machines.  So it's worth putting a some thought into.

 Surfaces that are 32bit, have all A,R,G,B channels (all channel are 8bit 0 to 255).   But  24bit surfaces only have 8bit Red, 8 bit Green and 8Bit Blue.   Where as 15bit  and 16 bit surfaces have reduced ranges on R,G,B.   15 surfaces have  5bit Red, 5Bits Green and 5Bits Blue.  16Bit surfaces have 5bits Red, 6bits Green and 5bits Blue.    So if we're reading pixels from the a 15bit or 16 bit surface and comparing the returned pixel values with a 32bit RGB (that's not colour 0 :) ),then we'll have to mask our 32bit value to make it compatible with the the surface.    

   

[pbcode]
   ; create four images, these images have a depth that's independent of the
   ; computers display depth.
   
   Width=100
   Height=100
   
    CreateFXImageEx 1,Width,Height,15       ; 15 bit image depth
    CreateFXImageEx 2,Width,Height,16       ; 16 bit image depth
    CreateFXImageEx 3,Width,Height,24       ; 24 bit image depth
    CreateFXImageEx 4,Width,Height,32       ; 32 bit image depth

   ; query our four images( #1 to #4) about their depth and
   ; the ARGB pixel mask for those surface depths.     

   For ThisIMage=1 to 4   
      ; Get IMage #1 Pixel Mask
      print "ThisImage:"+Str$(Thisimage)
      print "Depth:"+str$(GetIMageDepth(ThisImage))
      print "Mask:"+hex$(Get_Pixel_Mask(ThisImage))
   next

   Sync
   waitkey
   

Function Get_Pixel_Mask(ThisIMage=0)
   select getImageDepth(ThisIMage)
         case 15
            Mask=$00f8f8f8
         case 16
            Mask=$00f8fCf8
         case 24
            Mask=$00ffffff
         case 32
            Mask=$ffffffff
   EndSelect
EndFunction Mask

[/pbcode]




 This Example Demonstrates the potential problem

 Here we're create a 15bit surface, drawing a purple circle onto this surface then trying to run through the pixels of the surface and change them to some random colour.  

[pbcode]

   ; Usage example.  
   Width=100
   Height=100
   
   ; create a image that's 15bits depth, regardless of what the display depth
   ; is
   CreateFXImageEx 1,Width,Height,15       ; 15 bit image depth
   rendertoimage 1
   

   ; make 24bit RGB colour value, to represent purple.  R=255, G=0, B=255
   ; each channel is 8bit
   ThisColour=ARgb(255,255,0,255)

   ; draw a coloured circle to the current surface.
   Circlec Width/2,Height/2,Width/2,true,ThisColour   



   ; Get the middle pixel RGB
    MiddlePixelRGB=Point(Width/2,Height/2)
   

   ; run through and convert all the Purple pixels to a random colour
      For ylp=0 to Height-1
         For xlp=0 to Width-1
               If Point(xlp,ylp) = ThisColour   
                  Dotc Xlp,Ylp,rndrgb()
               endif
         next
      next


   rendertoscreen
   
   
   drawimage 1,100,100,false

   print "32bit Purple"
   print  hex$(ThisColour)

   
   print "Colour Read from surface"
   print  hex$(MiddlePixelRGB)
   

   Sync
   waitkey
   
[/pbcode]

 If you run this, it won't work.   It fails because we're comparing the 32bit RGB value, with the truncated value that's returned to us when reading from the 15bit surface.  Obviously a 15bit surface have less colour ranges in R,G,B.  


 This Example Demonstrates the solution using the mask function above

  To solve this type of issue we just mask our 32bit colour by the surface mask that we're reading from. This will convert our 32bit colour into something that's comparable.

[pbcode]

   ; Usage example.  
   Width=100
   Height=100
   
   ; create a image that's 15bits depth, regardless of what the display depth
   ; is
   CreateFXImageEx 1,Width,Height,15       ; 15 bit image depth
   rendertoimage 1
   

   ; make 24bit RGB colour value, to represent purple.  R=255, G=0, B=255
   ; each channel is 8bit
   ThisColour=ARgb(255,255,0,255)

   ; draw a coloured circle to the current surface.
   Circlec Width/2,Height/2,Width/2,true,ThisColour   



   ; Get the middle pixel RGB
    MiddlePixelRGB=Point(Width/2,Height/2)
   

   ; run through and convert all the Purple pixels to a random colour

   ThisColourMaskedForsurface=ThisColour and Get_Pixel_Mask(1)

      For ylp=0 to Height-1
         For xlp=0 to Width-1
               If Point(xlp,ylp) = ThisColourMaskedForsurface
                  Dotc Xlp,Ylp,rndrgb()
               endif
         next
      next


   rendertoscreen
   
   
   drawimage 1,100,100,false

   print "32bit Purple"
   print  hex$(ThisColour)

   print "32bit Purple masked for the 15bit surface"
   print hex$(ThisColourMaskedForsurface)

   print "Colour Read from surface"
   print  hex$(MiddlePixelRGB)
   
   Sync
   waitkey
   

Function Get_Pixel_Mask(ThisIMage=0)
   select getImageDepth(ThisIMage)
         case 15
            Mask=$00f8f8f8
         case 16
            Mask=$00f8fCf8
         case 24
            Mask=$00ffffff
         case 32
            Mask=$ffffffff
   EndSelect
EndFunction Mask

[/pbcode]