General purpose transparency in 24 bits - all OS

Share your advanced PureBasic knowledge/code with the community.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

General purpose transparency in 24 bits - all OS

Post by netmaestro »

Code: Select all

; Demo: General purpose transparent drawing in 24 bits
; Authors: Lloyd Gallant (netmaestro): original idea
           wilbert: improvements for speed and efficiency 

DeclareModule filters
  Declare SetTransparentColor(color.l)
  Declare TransparentFilter(x, y, sourcecolor.l, targetcolor.l)
EndDeclareModule


Module filters
  Global transcolor.l
  
  Procedure SetTransparentColor(color.l)
    transcolor.l = color | $FF<<24
  EndProcedure

  Procedure TransparentFilter(x, y, sourcecolor.l, targetcolor.l)
    EnableASM
    mov eax, sourcecolor
    cmp eax, transcolor
    !jne .cont
    mov eax, targetcolor
    !.cont:
    ProcedureReturn
    DisableASM  
  EndProcedure
EndModule

UseModule filters

CreateImage(0, 256,256,24,RGB(255,0,255)) ;Pink is the transparent color
StartDrawing(ImageOutput(0))
  Box(96,96,64,64,#Blue)
StopDrawing()

OpenWindow(0,0,0,640,480,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
SetWindowColor(0, #White)
CanvasGadget(0, 180,80,256,256)

StartDrawing(CanvasOutput(0))
  DrawingMode(#PB_2DDrawing_CustomFilter)
  CustomFilterCallback(@TransparentFilter())
  SetTransparentColor(RGB(255,0,255))
  DrawImage(ImageID(0), 0, 0)
StopDrawing()

Repeat : EventID = WaitWindowEvent()  
Until EventID = #PB_Event_CloseWindow
Note that the posted code has been improved by contributors on the forum so some replies may not make quite as much sense as they originally did. But I judge it less confusing to post the latest and best code in the first post. Credit is gratefully given where it is due.
Last edited by netmaestro on Mon Feb 13, 2017 12:18 pm, edited 9 times in total.
BERESHEIT
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: General purpose transparency in 24 bits - all OS

Post by wilbert »

Is there any advantage to using a Static variable compared to a Global for transcolor ?
Using a Global would probably make the callback procedure faster since you could remove the code to set transcolor from the procedure.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: General purpose transparency in 24 bits - all OS

Post by netmaestro »

I wrote it this way because I wanted to avoid using a global for the color. As SetTransparentColor() is called only once for each whole image, there should be no speed gain to be had by using a global as you still have to set the global once and then draw rather than set the static once and then draw. I'm just not a fan of global variables and I like to find ways to accomplish goals without using them. Let me say, not "no speed gain" as the static version does involve a test at each pixel drawn. A test is cheap, but is it cheap enough to warrant the avoidance of a global? To me, yes. To the average user, not sure. I haven't done exhaustive tests. Ideally I'd like the team to add an optional lParam parameter to the callback but they probably won't do that so this is my way of doing the next best thing. But I defer to your judgment when it comes to speed. If you say the global is faster I'll take your word.
Last edited by netmaestro on Mon Feb 13, 2017 12:25 pm, edited 3 times in total.
BERESHEIT
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: General purpose transparency in 24 bits - all OS

Post by netmaestro »

Btw wilbert does this code produce the desired results in OSX? I ask because when we were working on our Gif decoders in 2013 I originally used this approach but was told by Mac users that a bug in PureBasic caused it to not work properly. So I reluctantly switched over to 32bits and depended on the alpha layer for transparency. Just wondering if that bug is a concern anymore or did they fix it in the meantime.
BERESHEIT
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: General purpose transparency in 24 bits - all OS

Post by wilbert »

With the 5.60 beta (required to support constants like #Blue), your code seems to work fine on OSX.
On OSX however, the internal format is always 32 bit even if you specify 24.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: General purpose transparency in 24 bits - all OS

Post by netmaestro »

On OSX however, the internal format is always 32 bit even if you specify 24.
Next time you're talking to Tim Cook, you have my permission to punch him in the face. Be sure to mention my name first so he understands it'll be OK. The Donald will back me up. (if he took his meds)
BERESHEIT
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: General purpose transparency in 24 bits - all OS

Post by walbus »

@Netmaestro
I love this simple and efficient methods
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: General purpose transparency in 24 bits - all OS

Post by netmaestro »

Walbus, hang on for a second or two. Demivec suggested to me this code, which might be faster:

Code: Select all

DeclareModule filters
  Declare SetTransparentColor(color)
  Declare TransparentFilter(x, y, sourcecolor, targetcolor)
EndDeclareModule


Module filters
  Global transcolor
  
  Procedure SetTransparentColor(color)
    transcolor = color | $FF<<24
  EndProcedure

  Procedure TransparentFilter(x, y, sourcecolor, targetcolor)
    If sourcecolor = transcolor
      ProcedureReturn targetcolor
    Else
      ProcedureReturn sourcecolor
    EndIf
  EndProcedure
EndModule


CreateImage(0, 256,256,24,RGB(255,0,255)) ;Pink is the transparent color
StartDrawing(ImageOutput(0))
  Box(96,96,64,64,#Blue)
StopDrawing()

OpenWindow(0,0,0,640,480,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
SetWindowColor(0, #White)
CanvasGadget(0, 180,80,256,256)

StartDrawing(CanvasOutput(0))
  DrawingMode(#PB_2DDrawing_CustomFilter)
  filters::SetTransparentColor(RGB(255,0,255))
  CustomFilterCallback(filters::@TransparentFilter())
  DrawImage(ImageID(0), 0, 0)
StopDrawing()

Repeat : EventID = WaitWindowEvent()  
Until EventID = #PB_Event_CloseWindow
By encapsulating the code in a module the global var is much less despicable as its scope ends with the module. It's probably better than what I posted as my posted code requires a test at each drawn pixel.
BERESHEIT
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: General purpose transparency in 24 bits - all OS

Post by walbus »

Yep, i make the same with the globals, in a module and good is

I would firstly use FilterCallback in my BF, but, all over it was not needed

Also it is a next stepp for trying FilterCallback for testing a available speed up
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: General purpose transparency in 24 bits - all OS

Post by wilbert »

netmaestro wrote:Walbus, hang on for a second or two. Demivec suggested to me this code, which might be faster:
Asm variation (probably slightly faster)

Code: Select all

DeclareModule filters
  Declare SetTransparentColor(color.l)
  Declare TransparentFilter(x, y, sourcecolor.l, targetcolor.l)
EndDeclareModule


Module filters
  Global transcolor.l
  
  Procedure SetTransparentColor(color.l)
    transcolor.l = color | $FF<<24
  EndProcedure

  Procedure TransparentFilter(x, y, sourcecolor.l, targetcolor.l)
    EnableASM
    mov eax, sourcecolor
    cmp eax, transcolor
    !jne .cont
    mov eax, targetcolor
    !.cont:
    ProcedureReturn
    DisableASM  
  EndProcedure
EndModule
Windows (x64)
Raspberry Pi OS (Arm64)
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: General purpose transparency in 24 bits - all OS

Post by walbus »

@Wilbert
Many thanks for this
Yep, i would ask you for this and also a little asm optimized variant for that

Code: Select all

  Macro color_distance
    If c1<>c2
      Protected r1=Red(c1), g1=Green(c1), b1=Blue(c1)
      Protected r2=Red(c2), g2=Green(c2), b2=Blue(c2)
      Protected diff_red=Abs(r1-r2), diff_green=Abs(g1-g2), diff_blue=Abs(b1-b2)
      Protected r.f=diff_red/255, g.f=diff_green/255, b.f=diff_blue/255
      ProcedureReturn (r+g+b)/3*100
    Else
      ProcedureReturn 0
    EndIf
  EndMacro
Last edited by walbus on Tue Mar 07, 2017 9:33 am, edited 1 time in total.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: General purpose transparency in 24 bits - all OS

Post by wilbert »

@Walbus,
It's a different question but if SSE2 is no problem, try something like this

Code: Select all

Procedure color_distance(c1, c2); SSE2
  !movd xmm0, [p.v_c1]
  !movd xmm1, [p.v_c2]
  !pslld xmm0, 8
  !pslld xmm1, 8
  !psadbw xmm0, xmm1
  !movd eax, xmm0     ; eax range [0, 765]
  !imul eax, 0x2176cc ; div by 7.65
  !add eax, 0x800000
  !shr eax, 24
  ProcedureReturn
EndProcedure
Windows (x64)
Raspberry Pi OS (Arm64)
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: General purpose transparency in 24 bits - all OS

Post by walbus »

@Wilbert
Many thanks wilbert, your kindly help is inexpensive :!:
Post Reply