Page 1 of 2

bitmap color fill

Posted: Wed Feb 24, 2021 11:28 pm
by chi
I stumbled upon an article on codeproject.com and in the first code section there are some ASM instructions to fill a bitmap with a specific color. But all attempts porting it to PB ended with an IMA on "rep stosd". My knowledge about ASM is pretty limited, so it would be awesome if someone could guide me in the right direction ;)

Code: Select all

lea     rdi, BitmapData
mov     rax, BitmapWidth
mov     rcx, BitmapHeight
mul     rcx
mov     rcx, rax
mov     rax, FillColor
rep     stosd
[/size]

Re: bitmap color fill

Posted: Thu Feb 25, 2021 2:47 am
by Keya
what's an "IMA"?
"! rep stosd" compiles fine
but what worries me about this code, is that while it's very cute and compact (and I love it in that respect!) - but it assumes perfect input data, it doesn't have any bounds/error-checking, which may be the cause of the problem.
We always have to be able to account for invalid/corrupt input data.
And for example, check out the BMP file format: https://en.wikipedia.org/wiki/BMP_file_format
There is a field that defines "Extra bit masks" which is either 12 or 16 bytes. There's also other fields related to "structure alignment". I'm not saying that's the problem, but something the published code doesn't account for. eg is it a 32-bit BMP? 24-bit? 16-bit? 8-bit? 4-bit? 1-bit? im guessing your code is assuming 32bit

Re: bitmap color fill

Posted: Thu Feb 25, 2021 8:15 am
by infratec
IllegalMemoryAccess

You need the informations of DrawingBuffer() and DrawingBufferPitch()
Else you write to wrong locations.

And for 24bit you have to be very carefull, since it is stored with 3 bytes and not with 4.
Your assembler stuff stores 4 bytes.

Re: bitmap color fill

Posted: Thu Feb 25, 2021 10:04 am
by Mijikai
Example fills a bitmap with a 24 or 32-bit Color:

Code: Select all

EnableExplicit

Procedure.i BitmapFillColor(*Bits,Width.i,Height.i,Color.i,Depth.i = 32)
  If *Bits And Width And Height
    If Depth = 24
      !mov rdi,[p.p_Bits]
      !mov eax,dword[p.v_Color]
      !mov rcx,[p.v_Width]
      !imul rcx,0x3
      !imul rcx,[p.v_Height]
      !rep stosb
      ProcedureReturn #True
    ElseIf Depth = 32
      !mov rdi,[p.p_Bits]
      !mov eax,dword[p.v_Color]
      !mov rcx,[p.v_Width]
      !imul rcx,[p.v_Height]
      !rep stosd
      ProcedureReturn #True
    EndIf
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure.i Main()
  Protected *bits
  Protected w.i
  Protected h.i
  Protected s.i
  If OpenConsole("")
    w = 128
    h = 64
    PrintN("PRESS ANY KEY - 24 Bit Test!")
    Input()
    s = (w * 3) * h
    *bits = AllocateMemory(s)
    If *bits
      BitmapFillColor(*bits,w,h,$FFFFFF,24)
      ShowMemoryViewer(*bits,s)
      FreeMemory(*bits)
    EndIf
    PrintN("PRESS ANY KEY - 32 Bit Test!")
    Input()
    s = (w * 4) * h
    *bits = AllocateMemory(s)
    If *bits
      BitmapFillColor(*bits,w,h,$FFFFFFFF,32)
      ShowMemoryViewer(*bits,s)
      FreeMemory(*bits)
    EndIf
    Input()
    CloseConsole()
  EndIf
  ProcedureReturn
EndProcedure

Main()

End

Re: bitmap color fill

Posted: Thu Feb 25, 2021 10:14 am
by wilbert
Mijikai wrote:Example fills a bitmap with a 24 or 32-bit Color:
This only works for 32 bit.
For 24 bit images you can only set a gray value from 0 - 255 but not a color.

Re: bitmap color fill

Posted: Thu Feb 25, 2021 10:29 am
by Mijikai
wilbert wrote:
Mijikai wrote:Example fills a bitmap with a 24 or 32-bit Color:
This only works for 32 bit.
For 24 bit images you can only set a gray value from 0 - 255 but not a color.
Ups, since its a byte transfer...
I dont thing there is a neat solution then.

Re: bitmap color fill

Posted: Thu Feb 25, 2021 12:26 pm
by Helle
For instructions like STOSD it´s a good idea set/clear explicit the Direction Flag before. In this case

Code: Select all

...
!cld     ;increment the index register
!stosd

Re: bitmap color fill

Posted: Thu Feb 25, 2021 2:21 pm
by chi
Thanks guys (especially Mijikai)! I might have a clue now what's going on here :D

wilbert wrote:
Mijikai wrote:Example fills a bitmap with a 24 or 32-bit Color:

This only works for 32 bit.
For 24 bit images you can only set a gray value from 0 - 255 but not a color.
I only need 32-bit images, so the 24-bit stuff is not a problem.

Helle wrote:For instructions like STOSD it´s a good idea set/clear explicit the Direction Flag before. In this case

Code: Select all

...
!cld     ;increment the index register
!stosd
[/size]Isn't the DF cleared on function entry anyways? It seems always set to 0.

This is what I'm going with...

Code: Select all

Procedure BitmapFillColor(Width.l, Height.l, ARGB.l=$FF000000)
  Protected img.l, bmi.BITMAPINFO
  bmi\bmiHeader\biSize     = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth    = Width
  bmi\bmiHeader\biHeight   = -Height
  bmi\bmiHeader\biPlanes   = 1
  bmi\bmiHeader\biBitCount = 32
  img = CreateDIBSection_(0, @bmi, #DIB_RGB_COLORS, @*bits, 0, 0)
  !mov  edi,[p.p_bits]
  !mov  ecx,[p.v_Width]
  !imul ecx,[p.v_Height]
  !mov  eax,[p.v_ARGB]
  !cld
  !rep  stosd
  ProcedureReturn img
EndProcedure

img.l = BitmapFillColor(300, 180, $FF00FF00)

OpenWindow(0, 0, 0, 320, 200, "", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ImageGadget(0, 10, 10, 0, 0, img)
DeleteObject_(img)
While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend

Re: bitmap color fill

Posted: Thu Feb 25, 2021 3:07 pm
by Mijikai
I fixed my code (thx Wilbert & Helle)

Now it works for 32 - 8 bit images:

Code: Select all


EnableExplicit

Procedure.i BitmapFillColor(*Bits,Width.i,Height.i,Color.i,Depth.i = 32)
  If *Bits And Width And Height
    If Depth = 32
      !mov rdi,[p.p_Bits]
      !mov eax,dword[p.v_Color]
      !mov rcx,[p.v_Width]
      !imul rcx,[p.v_Height]
      !cld
      !rep stosd
      ProcedureReturn #True
    ElseIf Depth > 7
      !lea r8,[p.v_Color]
      !mov r9,[p.p_Bits]
      !mov rdx,[p.v_Depth]
      !shr rdx,0x3
      !mov rax,[p.v_Width]
      !imul rax,[p.v_Height]
      !cld
      !@@:
      !mov rsi,r8
      !mov rdi,r9
      !mov rcx,rdx
      !rep movsb
      !add r9,rdx
      !dec rax
      !test rax,rax
      !jne @b
      ProcedureReturn #True
    EndIf
  EndIf
  ProcedureReturn #False
EndProcedure


Procedure.i Main()
  Protected *bits
  Protected w.i
  Protected h.i
  Protected s.i
  If OpenConsole("")
    w = 128
    h = 64
    PrintN("PRESS ANY KEY - 24 Bit Test!")
    Input()
    s = (w * 3) * h
    *bits = AllocateMemory(s)
    If *bits
      BitmapFillColor(*bits,w,h,$332211,24)
      ShowMemoryViewer(*bits,s)
      FreeMemory(*bits)
    EndIf
    PrintN("PRESS ANY KEY - 32 Bit Test!")
    Input()
    s = (w * 4) * h
    *bits = AllocateMemory(s)
    If *bits
      BitmapFillColor(*bits,w,h,$44332211,32)
      ShowMemoryViewer(*bits,s)
      FreeMemory(*bits)
    EndIf
    Input()
    CloseConsole()
  EndIf
  ProcedureReturn
EndProcedure

Main()

End

Re: bitmap color fill

Posted: Thu Feb 25, 2021 3:37 pm
by Helle
@chi:

Code: Select all

Procedure BitmapFillColor(Width.l, Height.l, ARGB.l=$FF000000)
  Protected img.l, bmi.BITMAPINFO
  bmi\bmiHeader\biSize     = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth    = Width
  bmi\bmiHeader\biHeight   = -Height
  bmi\bmiHeader\biPlanes   = 1
  bmi\bmiHeader\biBitCount = 32
  img = CreateDIBSection_(0, @bmi, #DIB_RGB_COLORS, @*bits, 0, 0)
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    !mov  edi,[p.p_bits]
    !mov  ecx,[p.v_Width]
    !imul ecx,[p.v_Height]
    !mov  eax,[p.v_ARGB]
;!cld
    !rep  stosd
  CompilerElse
    !mov  rdi,[p.p_bits]
    !mov  rcx,[p.v_Width]
    !imul rcx,[p.v_Height]
    !mov  rax,[p.v_ARGB]
;!cld
    !rep  stosd
  CompilerEndIf
  ProcedureReturn img
EndProcedure
;...
!std     ;e.g. from another part of your program (und du suchst dich dumm und dämlich :-) )
;...
img = BitmapFillColor(300, 180, $FF00FF00)

OpenWindow(0, 0, 0, 320, 200, "", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ImageGadget(0, 10, 10, 0, 0, img)
While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend
DeleteObject_(img)

Re: bitmap color fill

Posted: Thu Feb 25, 2021 4:34 pm
by chi
@Helle: Oh, OK... Guess I have a lot to learn. Thanks for the clarification!

@Mijikai: Is there a reason why you use

Code: Select all

!mov eax,dword[p.v_Color]
[/size] instead of

Code: Select all

!mov rax,[p.v_Color]
[/size]Something I should be aware of?

Re: bitmap color fill

Posted: Thu Feb 25, 2021 6:16 pm
by Mijikai
chi wrote: @Mijikai: Is there a reason why you use

Code: Select all

!mov eax,dword[p.v_Color]
[/size] instead of

Code: Select all

!mov rax,[p.v_Color]
[/size]Something I should be aware of?
It results in smaller code.

Re: bitmap color fill

Posted: Fri Feb 26, 2021 5:28 am
by chi
Mijikai wrote:It results in smaller code.
Actually I "learned" that a few month ago, but I already forgot :oops:. Thanks for the reminder ^^

Re: bitmap color fill

Posted: Sat Feb 27, 2021 12:24 pm
by Olli
All this could be considered useless !

Code: Select all

Box(x, y, w, h, c)
Box() is as fast and short !
However

Code: Select all

! Rep ScaSD ; search a RGBA color
This code above is useful, not having native equivalent. This scans (searches) a RGBA color. And this uses the same general registers (and direction flag) to process. So... This is no so useless !

Just be careful with the direction flag : He must be always set to decreasing status, after the ASM routine, else you will crash PureBasic !

And to search a primary color (red, green, blue or alpha value), an optimum (minimum or maximum color value), or to set to gray (or grey if Shakespeare wants it, by calculating the colors distances), AVX ASM statements are required.

Re: bitmap color fill

Posted: Sat Feb 27, 2021 1:30 pm
by Mijikai
Olli wrote:All this could be considered useless !

Code: Select all

Box(x, y, w, h, c)
Box() is as fast and short !
Its useable if you can accept all the limitations that come with it.

The Box() command requires the creation of a device context and the allocation of additional memory.
All that is not needed here.