Flip sprite horizontally 2D bug

Just starting out? Need help? Post your questions and find answers here.
OgreVorbis
User
User
Posts: 77
Joined: Thu Jan 16, 2020 10:47 pm

Flip sprite horizontally 2D bug

Post by OgreVorbis »

Hey,

I'm relatively new to PB, but I had been using the demo for a while.
I am now trying to make a simple game to work on my skills. In the game, all of the sprites need to be flipped horizontally in order to be realistic. Flipping the files would double the sprite count.

So I found this code from another old post on here. I was unable to find any other code. The problem is that on the first loop "For j = 0", it says invalid memory access (read error at address 0). The poster said it was working, but it doesn't work for me.

In my code I use PNG decoder and then I just do a bunch of LoadSprites, then I CopySprite, then I flip it with this code, then I DisplayTransparentSprite.

I'd appreciate some help. This is the one thing that I really think needs to be added to the built in sprite library. It is something very commonly needed and it seems that PB is very good at providing extensive built-in functions, but in this case it seems lacking.

Code: Select all

Procedure HFlipSprite(SpriteNumber.l)
  SpriteAddress.l
  ArrayAddress.l
  StartDrawing(SpriteOutput(SpriteNumber))
    DrawingBuffer = DrawingBuffer()
    DrawingBufferPitch = DrawingBufferPitch()
    SpriteHeight = SpriteHeight(SpriteNumber)
    SpriteWidth = SpriteWidth(SpriteNumber)
    Dim Array.l(SpriteHeight - 1, SpriteWidth - 1)
    MemoryLength = SpriteHeight * SpriteWidth * 4 - 4
    ArrayAddress = @Array()
    For i = 0 To SpriteHeight - 1
      SpriteAddress = DrawingBuffer + DrawingBufferPitch * i
      For j = 0 To SpriteWidth - 1
        !  MOV     eax, dword [esp+4] ; PokeL(ArrayAddress, PeekL(SpriteAddress))
        !  MOV     ebx, [eax]
        !  MOV     eax, dword [esp+8]
        !  MOV     [eax], ebx
        ArrayAddress + 4
        SpriteAddress + 4
      Next
    Next
    For i = 0 To SpriteHeight - 1
      For j = 0 To (SpriteWidth - 1) / 2
        x = Array(i, j)
        Array(i, j) = Array(i, SpriteWidth - 1 - j)
        Array(i, SpriteWidth - 1 - j) = x
      Next
    Next
    ArrayAddress = @Array()
    For i = 0 To SpriteHeight - 1
      SpriteAddress = DrawingBuffer + DrawingBufferPitch * i
      For j = 0 To SpriteWidth - 1
        !  MOV     eax, dword [esp+8] ; PokeL(SpriteAddress, PeekL(ArrayAddress))
        !  MOV     ebx, [eax]
        !  MOV     eax, dword [esp+4]
        !  MOV     [eax], ebx
        ArrayAddress + 4
        SpriteAddress + 4
      Next
    Next
  StopDrawing()
EndProcedure
My blog/software site: http://dosaidsoft.com/
Alex777
User
User
Posts: 47
Joined: Sun Nov 16, 2008 12:47 am
Location: Cayman Is.
Contact:

Re: Flip sprite horizontally 2D bug

Post by Alex777 »

Try this (works for me). You need to call DisableBackfaceCulling() once at startup, then Transform() should do it for you.

Code: Select all

Procedure DisableBackfaceCulling()
    ; call at initialization to disable backface culling
    ;     from viewtopic.php?f=16&t=43718
    
    Protected pd3d.IDirect3DDevice9
    
    EnableASM
        !extrn _PB_Screen_Direct3DDevice
        !MOV dword EAX, [_PB_Screen_Direct3DDevice]
        !MOV dword [p.v_pd3d], EAX
    DisableASM
    
    pd3d\SetRenderState(22, 1)
    pd3d\SetRenderState(7, 0)

EndProcedure

Procedure Transform(sprID.i, type.i)
    ; transform sprID - the transformation is 'sticky'
    ; requires that backface culling be disabled
    ; type.i:
    ;    0 = restore normal sprite
    ;    1 = mirror sprite horizontally
    ;    2 = flip sprite vertically
    ;    3 = iso floor tile
    ;    4 = iso left wall tile
    ;    5 = iso right wall tile
    
    Protected wid.i = SpriteWidth(sprID)
    Protected ht.i = SpriteHeight(sprID)
    
    Select type
            
        Case 0                                   ; restore
            TransformSprite(sprID, 0, 0, 1.0, wid, 0, 1.0, wid, ht, 1.0, 0, ht, 1.0)
            
        Case 1                                   ; mirror
            TransformSprite(sprID, wid, 0, 1.0, 0, 0, 1.0, 0, ht, 1.0, wid, ht, 1.0)
            
        Case 2                                   ; flip
            TransformSprite(sprID, 0, ht, 1.0, wid, ht, 1.0, wid, 0, 1.0, 0, 0, 1.0)
            
        Case 3                                   ; iso floor tile
            wid = wid + 1                        ; appears necessary
            TransformSprite(sprID, wid, 0, 1.0, wid * 2, ht * 0.5, 1.0, wid, ht, 1.0, 0, ht * 0.5, 1.0)
                            
        Case 4                                   ; iso left wall tile
            TransformSprite(sprID, 0, ht * 0.5, 1.0, wid, 0, 1.0, wid, ht, 1.0, 0, ht * 1.5, 1.0)
            
        Case 5                                   ; iso right wall tile
            TransformSprite(sprID, 0, 0, 1.0, wid, ht * 0.5, 1.0, wid, ht * 1.5, 1.0, 0, ht, 1.0)
            
    EndSelect
    
EndProcedure
OgreVorbis
User
User
Posts: 77
Joined: Thu Jan 16, 2020 10:47 pm

Re: Flip sprite horizontally 2D bug

Post by OgreVorbis »

OK, thanks :)

I'll test it when I get back to my development comp.

Does this actually alter the sprite in memory or is it applying this effect every time the sprite is drawn. Cause I just want to create a copy of each sprite in memory flipped. I've got an animation routine that this may mess with if it's doing it real time.

So can I do a CopySprite and apply this to it and it actually changed the sprite in memory?
My blog/software site: http://dosaidsoft.com/
Alex777
User
User
Posts: 47
Joined: Sun Nov 16, 2008 12:47 am
Location: Cayman Is.
Contact:

Re: Flip sprite horizontally 2D bug

Post by Alex777 »

The transform is sticky. It alters the sprite in memory.
User avatar
Demivec
Addict
Addict
Posts: 4089
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Flip sprite horizontally 2D bug

Post by Demivec »

@OgreVorbis: Here is a modified and corrected version of the procedure you posted. I removed the assembler code. It has not been optimized for speed because if it works for you that is good enough :) .

You would just CopySprite and apply this to it and it will changed the sprite in memory.

Code: Select all

;updated for PB v5.71 LTS
Procedure HFlipSprite(SpriteNumber)
  Protected ArrayAddress, DrawingBuffer, DrawingBufferPitch, SpriteHeight_M1, SpriteWidth
  Protected MemoryLength, i, j, x
  
  StartDrawing(SpriteOutput(SpriteNumber))
    DrawingBuffer = DrawingBuffer()
    DrawingBufferPitch = DrawingBufferPitch()
    SpriteHeight_M1 = SpriteHeight(SpriteNumber) - 1
    SpriteWidth = SpriteWidth(SpriteNumber)
    Dim Array.l(SpriteHeight_M1, SpriteWidth - 1)
    MemoryLength = SpriteWidth * SizeOf(Long)
    ArrayAddress = @Array()
    For i = 0 To SpriteHeight_M1
      CopyMemory(DrawingBuffer + DrawingBufferPitch * i, ArrayAddress, MemoryLength)
      ArrayAddress + MemoryLength
    Next
    For i = 0 To SpriteHeight_M1
      For j = 0 To (SpriteWidth - 1) / 2
        x = Array(i, j)
        Array(i, j) = Array(i, SpriteWidth - 1 - j)
        Array(i, SpriteWidth - 1 - j) = x
      Next
    Next
    ArrayAddress = @Array()
    For i = 0 To SpriteHeight_M1
      CopyMemory(ArrayAddress, DrawingBuffer + DrawingBufferPitch * i, MemoryLength)
      ArrayAddress + MemoryLength
    Next
  StopDrawing()
EndProcedure
OgreVorbis
User
User
Posts: 77
Joined: Thu Jan 16, 2020 10:47 pm

Re: Flip sprite horizontally 2D bug

Post by OgreVorbis »

Thank you very much. Works perfectly. And speed is not an issue cause I run this only when the game loads.

As a side note: I wish I had started purebasic earlier. I am growing to like it more than C#. It's native and small and provides a similar feedback to what I used to get when I started programming in QBASIC many years ago. Amazing that it's made by just one guy AFAIK. Really a masterpiece.
My blog/software site: http://dosaidsoft.com/
Post Reply