bitmap color fill

Bare metal programming in PureBasic, for experienced users
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

bitmap color fill

Post 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]
Et cetera is my worst enemy
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Re: bitmap color fill

Post 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
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: bitmap color fill

Post 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.
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: bitmap color fill

Post 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
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: bitmap color fill

Post 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.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: bitmap color fill

Post 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.
Helle
Enthusiast
Enthusiast
Posts: 178
Joined: Wed Apr 12, 2006 7:59 pm
Location: Germany
Contact:

Re: bitmap color fill

Post 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
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: bitmap color fill

Post 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
Last edited by chi on Fri Feb 26, 2021 5:29 am, edited 1 time in total.
Et cetera is my worst enemy
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: bitmap color fill

Post 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
Helle
Enthusiast
Enthusiast
Posts: 178
Joined: Wed Apr 12, 2006 7:59 pm
Location: Germany
Contact:

Re: bitmap color fill

Post 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)
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: bitmap color fill

Post 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?
Et cetera is my worst enemy
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: bitmap color fill

Post 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.
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: bitmap color fill

Post 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 ^^
Et cetera is my worst enemy
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: bitmap color fill

Post 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.
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: bitmap color fill

Post 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.
Post Reply