Page 1 of 1

BitFields for PB

Posted: Mon Apr 18, 2016 8:57 am
by idle
A Bitfield wrangler (transforming data to a different format)

simplifies using bitfields
SetBitFieldPointer(*bitfield,@Some_var)
SetBitField(*bitfield,field_index,value)
ReSetBitField((*bitfield,field_index,value)
GetBitField(*bitfield,field_index)

supports byte, word, long and integer width fields

added a reset macro to clear and set a bitfield in case you need to over write a field

Code: Select all

;BitField wrangler  
;idle 19/4/2016 
;supports byte, word, long and integer width fields 
;usage see example 

Structure BitField 
  *bits.Integer  
  Size.l 
  BF_Index.l 
  BF_Offset.l 
  BF_Mask.i  
  Array BF.i(1,0) 
EndStructure  

Procedure NewBitField(NumFields,Address=0,size=4) 
  Protected *this.BitField 
  *this = AllocateStructure(BitField) 
  If *this
    *this\size = size 
    *this\bits = Address 
     ReDim *this\bf(1,NumFields) 
     ProcedureReturn *this 
  EndIf  
EndProcedure  

Procedure FreeBitField(*BitField) 
  FreeStructure(*BitField) 
EndProcedure   
  
Procedure AddBitField(*BitField.BitField,NumBits) 
  Select *BitField\size 
    Case 1 
      *BitField\BF_Mask = $FF
      *BitField\BF_Mask >> (8-NumBits)
    Case 2 
      *BitField\BF_Mask = $FFFF
      *BitField\BF_Mask >> (16-NumBits)
    Case 4   
      *BitField\BF_Mask = $FFFFFFFF
      *BitField\BF_Mask >> (32-NumBits)
    Case 8 
      *BitField\BF_Mask = $FFFFFFFFFFFFFFFF
      *BitField\BF_Mask >> (64-NumBits)
  EndSelect     
  
  *BitField\bf(0,*BitField\BF_Index) = (*BitField\BF_Mask << *BitField\BF_Offset) 
  *BitField\bF(1,*BitField\BF_Index) = *BitField\BF_Offset 
  *BitField\BF_Offset + NumBits 
  *BitField\BF_Index+1
EndProcedure  

Macro GetBitField(BitField,Index) 
  ((BitField\bits\i & BitField\bf(0,index)) >> BitField\bf(1,index)) 
EndMacro   

Macro SetBitField(BitField,index,val)
   BitField\bits\i | (val << BitField\bf(1,index))
EndMacro   

Macro ReSetBitField(BitField,index,val) 
  BitField\bits\i & ~BitField\bf(0,index) | (val << BitField\bf(1,index))
EndMacro    

Macro SetBitFieldPointer(BitField,Address) 
  BitField\bits = Address 
EndMacro   

;Example of a date and time 

Global The_date.l, Future_date.l, strdate.s, Month.l=4

Global *date.BitField = NewBitField(5); define a bitfield wrangler specifying number of field entries  

Enumeration  ;optional set up indicies for the bitfield    
  #date_day         
  #date_month  
  #date_year  
  #date_hour  
  #date_min   
EndEnumeration 

AddBitField(*date,5)  ;Add the bitfields specifiying the required bit widths 
AddBitField(*date,4)         
AddBitField(*date,12)  
AddBitField(*date,5)
AddBitField(*date,6) 

;use the *date.bitfield wrangler macros   
SetBitFieldPointer(*date,@The_date) ;set the wrangler to work on the var "The_date"  

SetBitField(*date,#date_day,18+1)  ;set the date and time    
SetBitField(*date,#date_month,month)  
SetBitField(*date,#date_year,2016)  
SetBitField(*date,#date_hour,1)
ReSetBitField(*date,#date_hour,16) ;clears and sets a field (just a longer opperation)  
SetBitField(*date,#date_min,59) 

Debug The_date ;check the var was set by the wrangler  

;extract the date into a string 
strdate + Str(GetBitField(*date,#date_day)) + "/"  
strdate + Str(GetBitField(*date,#date_month)) + "/"
strdate + Str(GetBitField(*date,#date_year)) + " " 
strdate + Str(GetBitField(*date,#date_hour)) + ":" 
strdate + Str(GetBitField(*date,#date_min)) 

Debug strdate 
strdate ="" 

Future_date = -300906349  ;future date a 100 years forward   
SetBitFieldPointer(*date,@future_date) ;point the wrangler to work with Future_date 
;extract it to a string 
strdate + Str(GetBitField(*date,#date_day)) + "/"   
strdate + Str(GetBitField(*date,#date_month)) + "/"
strdate + Str(GetBitField(*date,#date_year)) + " " 
strdate + Str(GetBitField(*date,#date_hour)) + ":" 
strdate + Str(GetBitField(*date,#date_min)) 

Debug strdate 

;done, free the wrangler  
FreeBitField(*date) 

Re: BitFields for PB

Posted: Tue Apr 19, 2016 6:34 am
by idle
updated to work with external variables only and added a better example

Re: BitFields for PB

Posted: Tue Apr 19, 2016 7:02 am
by davido
@idle,
Interesting demo.
Thank you for sharing. :D

Re: BitFields for PB

Posted: Tue Apr 19, 2016 8:02 am
by idle
Thanks Davido
I just added a macro to clear and set a bitfield "ReSetBitField" so you can overwrite a bit field

Re: BitFields for PB

Posted: Wed Apr 20, 2016 8:33 am
by Keya
I came up with this function after reading wikipedia and seeing samples on the web about converting from 24bit truecolor to 8bit, where it stores 3 bits for red, 3 for green, and 2 for blue

Code: Select all

Procedure.i Truecolor24to8bit(r,g,b)
  ProcedureReturn (((r*8)/256) << 5) | (((g*8)/256) << 2) | ((b*4)/256)
EndProcedure
but im not sure how to then convert it back from a single integer into the red, green and blue values, can i use your bitfields for this or?
Thankyou!

Re: BitFields for PB

Posted: Wed Apr 20, 2016 9:11 am
by wilbert
Keya wrote:I came up with this function after reading wikipedia and seeing samples on the web about converting from 24bit truecolor to 8bit, where it stores 3 bits for red, 3 for green, and 2 for blue

Code: Select all

Procedure.i Truecolor24to8bit(r,g,b)
  ProcedureReturn (((r*8)/256) << 5) | (((g*8)/256) << 2) | ((b*4)/256)
EndProcedure
but im not sure how to then convert it back from a single integer into the red, green and blue values, can i use your bitfields for this or?
Thankyou!
It's the palette MSX2 used for "Screen 8" 8)
Fastest way to convert back is a lookup table :)

Getting r, g and b using integer math

Code: Select all

For i = 0 To 255
  r = ((i & %11100000) * 73) >> 6
  g = ((i & %00011100) * 73) >> 3
  b = (i & %00000011) * 85
  Debug Hex(RGBA(r, g, b, 255), #PB_Long)
Next

Re: BitFields for PB

Posted: Wed Apr 20, 2016 9:27 am
by idle
yes like this but a lookup table would be faster like wilbert said

Code: Select all

Enumeration ;enum indices lowest bits to highest bits 
  #mblue
  #mgreen
  #mred 
EndEnumeration 

Define color.a 

*col.BitField = NewBitField(3,@color,1) ;define a template for 1 byte 
AddBitField(*col,2)  ;set the bit widths
AddBitField(*col,3)
AddBitField(*col,3)

Procedure.i Truecolor24to8bit(r,g,b)
  ProcedureReturn (((r*8)/256) << 5) | (((g*8)/256) << 2) | ((b*4)/256)
EndProcedure

r = 127
g = 127
b = 255 

color = Truecolor24to8bit(r,g,b) 
 
Debug (r*8)/256
Debug (g*8)/256
Debug (b*4)/256

Debug GetBitField(*col,#mred) ;extract in what order you want 
Debug GetBitField(*col,#mgreen)
Debug GetBitField(*col,#mblue) 


Re: BitFields for PB

Posted: Wed Apr 20, 2016 4:42 pm
by Keya
brilliant, thankyou both very much!!!

MSX2? i hadn't heard of that until yesterday when i came across a demo of netmaestro's that offers MSX2 (wiki suggests its an entire computer system, not so much a graphics thing!? but wiki has it here), but also he came up with some adaptive palette method which seemed to have great results :) it's all above my head though so i was hoping to start out with this 'simple' method first lol. Thankyou again both of you so much!!! :)

Re: BitFields for PB

Posted: Wed Apr 20, 2016 5:22 pm
by wilbert
Off-topic
Keya wrote:MSX2 (wiki suggests its an entire computer system, not so much a graphics thing!?
Yes, it was a very nice system back in the '80s.
It was an open standard implemented by different companies. The one we had at home was a Philips NMS 8250 but there were also from Sony, Panasonic etc.
There was even a NMS 8280 from Philips which could capture stills in this 3-3-2 palette from a video input :)
Basic and DOS version it had were made by Microsoft and you could also use Z80 assembler to speed up some routines :shock: 8)