Page 1 of 1

General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 9:00 am
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.

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 10:21 am
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.

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 11:02 am
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.

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 11:11 am
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.

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 11:20 am
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.

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 11:23 am
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)

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 11:28 am
by walbus
@Netmaestro
I love this simple and efficient methods

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 11:34 am
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.

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 11:43 am
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

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 12:00 pm
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

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 12:20 pm
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

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 12:57 pm
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

Re: General purpose transparency in 24 bits - all OS

Posted: Mon Feb 13, 2017 1:49 pm
by walbus
@Wilbert
Many thanks wilbert, your kindly help is inexpensive :!: