Page 1 of 3

2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 2:44 pm
by dige
hi guys,

I would like to change the view for 360 degree panoramic images and need an image rolling function.
I have considered two options for this. Using DrawImage and using GrabImage to scroll the content.
GrabImage seems to be much more performant. But is it any faster? So far it still looks quite jerky.

Image

If you need a 360 Grad Pano: http://u.pc.cd/mvx7

I can't wait to see what else is possible here :D

Code: Select all

UseJPEGImageDecoder()

Procedure.b isShiftKey()
  If GetAsyncKeyState_(#VK_SHIFT) & $8000
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure
Procedure.b isStrgKey()
  If GetAsyncKeyState_ (#VK_LCONTROL) & $8000 Or GetAsyncKeyState_ (#VK_RCONTROL) & $8000
  ProcedureReturn #True
Else
  ProcedureReturn #False
EndIf
EndProcedure

Procedure RenderImage(ImgID)
  If StartDrawing(CanvasOutput(0))
    DrawImage(ImageID(ImgID), 0, 0)
    StopDrawing()
  EndIf
EndProcedure

Procedure RollImage_Variante_1 (ImgID, direction, offset)
  Protected ImgWidth = ImageWidth(ImgID)
  Protected ImgHeight = ImageHeight(ImgID)
  Protected TempImg
  
  TempImg = CreateImage(#PB_Any, ImgWidth, ImgHeight)
  
  If TempImg
    If StartDrawing(ImageOutput(TempImg))
      Select direction
        Case 1 ; left
          DrawImage(ImageID(ImgID), -offset, 0)
          DrawImage(ImageID(ImgID), ImgWidth - offset, 0)
        Case 2 ; right
          DrawImage(ImageID(ImgID), offset, 0)
          DrawImage(ImageID(ImgID), -ImgWidth + offset, 0)
        Case 4 ; up
          DrawImage(ImageID(ImgID), 0, -offset)
          DrawImage(ImageID(ImgID), 0, ImgHeight - offset)
        Case 8 ; down
          DrawImage(ImageID(ImgID), 0, offset)
          DrawImage(ImageID(ImgID), 0, -ImgHeight + offset)
      EndSelect
      StopDrawing()
    EndIf
    CopyImage(TempImg, ImgID)
    FreeImage(TempImg)
  
  EndIf
EndProcedure

Procedure RollImage (ImgID, direction, offset) ; 1 left, 2 right, 4, up, 8 down
  
  Protected ImgID_1, ImgID_2
  
  If isShiftKey() : offset * 5 : EndIf
  If isStrgKey()  : offset * 10 : EndIf
  
  If direction & 1 ; left
    ImgID_1 = GrabImage(ImgID, #PB_Any, 0, 0, offset, ImageHeight(ImgID))
    ImgID_2 = GrabImage(ImgID, #PB_Any, offset, 0, ImageWidth(ImgID) - offset, ImageHeight(ImgID))
    
    If StartDrawing(ImageOutput(ImgID))
      DrawImage(ImageID(ImgID_2), 0, 0)
      DrawImage(ImageID(ImgID_1), ImageWidth(ImgID) - offset, 0)
      StopDrawing()
    EndIf
  EndIf
  
  If direction & 2 ; right
    ImgID_1 = GrabImage(ImgID, #PB_Any, ImageWidth(ImgID) - offset, 0, offset, ImageHeight(ImgID))
    ImgID_2 = GrabImage(ImgID, #PB_Any, 0, 0, ImageWidth(ImgID) - offset, ImageHeight(ImgID))
    
    If StartDrawing(ImageOutput(ImgID))
      DrawImage(ImageID(ImgID_1), 0, 0)
      DrawImage(ImageID(ImgID_2), offset, 0)
      StopDrawing()
    EndIf
  EndIf
  
  If direction & 4 ; up
    ImgID_1 = GrabImage(ImgID, #PB_Any, 0, 0, ImageWidth(ImgID),offset)
    ImgID_2 = GrabImage(ImgID, #PB_Any, 0, offset, ImageWidth(ImgID), ImageHeight(ImgID) - offset)
    
    If StartDrawing(ImageOutput(ImgID))
      DrawImage(ImageID(ImgID_2), 0, 0)
      DrawImage(ImageID(ImgID_1), 0, ImageHeight(ImgID) - offset)
      StopDrawing()
    EndIf
  EndIf
  
  If direction & 8 ; down
    ImgID_1 = GrabImage(ImgID, #PB_Any, 0, ImageHeight(ImgID) - offset, ImageWidth(ImgID), offset)
    ImgID_2 = GrabImage(ImgID, #PB_Any, 0, 0, ImageWidth(ImgID), ImageHeight(ImgID) - offset)
    
    If StartDrawing(ImageOutput(ImgID))
      DrawImage(ImageID(ImgID_1), 0, 0)
      DrawImage(ImageID(ImgID_2), 0, offset)
      StopDrawing()
    EndIf
    
  EndIf 
  
  If IsImage(ImgID_1) : FreeImage(ImgID_1) : EndIf
  If IsImage(ImgID_2) : FreeImage(ImgID_2) : EndIf
EndProcedure

OpenWindow(0, 0, 0, 100, 200, "", #PB_Window_SystemMenu | #PB_Window_Maximize)
CanvasGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), #PB_Canvas_Keyboard)

file.s = OpenFileRequester("Select Jpg image", "Pano_360.jpg", "Image (*.jpg;*.jpeg)|*.jpg;*.jpeg|All files (*.*)|*.*", 0)

If file <> ""
  ImgID = LoadImage(#PB_Any, file)
  ResizeImage(ImgID, GadgetWidth(0), GadgetHeight(0))
  RenderImage(ImgID)
  
Else

  ImgID = CreateImage(#PB_Any, GadgetWidth(0), GadgetHeight(0), 24, #White)

  If StartDrawing(ImageOutput(ImgID))
    
    For i = 1 To 100
      
      Box (Random(ImageWidth(ImgID)-300), Random(ImageHeight(ImgID)-300), Random(300), Random(300), Random($FFFFFF))
      Circle( Random(ImageWidth(ImgID)-150), Random(ImageHeight(ImgID)-150), Random(300), Random($FFFFFF))
      
    Next
    StopDrawing()
  EndIf
EndIf




; Performance Test
DTG = ElapsedMilliseconds()
For i = 1 To 200
  RollImage_Variante_1(ImgID, 1, 10)
Next
MessageRequester( "Variante 1", Str(ElapsedMilliseconds() - DTG) + "ms")

DTG = ElapsedMilliseconds()
For i = 1 To 200
  RollImage(ImgID, 1, 10)
Next
MessageRequester( "Variante 2", Str(ElapsedMilliseconds() - DTG) + "ms")





SetActiveGadget(0)

Repeat
  Event = WaitWindowEvent()
  
  If Event = #PB_Event_Gadget And EventGadget() = 0

    If EventType() = #PB_EventType_KeyDown 
      
      key = GetGadgetAttribute(0, #PB_Canvas_Key)
      
      If key = #PB_Shortcut_Left Or key = #PB_Shortcut_Pad4
        RollImage(ImgID, 1, 10)
        
      ElseIf key =#PB_Shortcut_Right Or key = #PB_Shortcut_Pad6
        RollImage(ImgID, 2, 10)
        
      ElseIf key =#PB_Shortcut_Up Or key = #PB_Shortcut_Pad8
        RollImage(ImgID, 4, 10)
        
      ElseIf key =#PB_Shortcut_Down Or key = #PB_Shortcut_Pad2
        RollImage(ImgID, 8, 10)
        
      ElseIf key = #PB_Shortcut_Pad7 ; left up
        RollImage(ImgID, 1|4, 10)
        
      ElseIf key = #PB_Shortcut_Pad1 ; left down
        RollImage(ImgID, 1|8, 10)
        
      ElseIf key = #PB_Shortcut_Pad9 ; right up
        RollImage(ImgID, 2|4, 10)
        
      ElseIf key = #PB_Shortcut_Pad3 ; right down
        RollImage(ImgID, 2|8, 10)
        
      EndIf  
        
      RenderImage(ImgID)
    EndIf
  EndIf  
  
Until Event = #PB_Event_CloseWindow

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 2:53 pm
by jacdelad
https://www.purebasic.fr/english/viewtopic.php?t=84497
this should help you, with some adaption, if needed.

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 3:09 pm
by dige
Thx Jacdelad, I'll take a look.


In the meantime, I asked Claude.ai the same question. The AI has revised it and asked me whether it should add extensions to improve the user experience.

This is the result. I am flashed :shock:

Code: Select all

UseJPEGImageDecoder()

#VK_SHIFT = 16
#VK_LCONTROL = 162
#VK_RCONTROL = 163

Global ImgID, LastMouseX, LastMouseY, IsMouseDown
Global ZoomFactor.f = 1.0
Global LastUpdateTime
Global VelocityX.f, VelocityY.f

Procedure.f Max(v1.f, v2.f)
  If v1 >= v2
    ProcedureReturn v1
  Else
    ProcedureReturn v2
  EndIf
EndProcedure

Procedure.f Min(v1.f, v2.f)
  If v1 <= v2
    ProcedureReturn v1
  Else
    ProcedureReturn v2
  EndIf
EndProcedure

Procedure.b IsKeyPressed(VirtualKey)
  ProcedureReturn Bool(GetAsyncKeyState_(VirtualKey) & $8000)
EndProcedure

Procedure RollImage(ImgID, deltaX, deltaY)
  Protected ImgWidth = ImageWidth(ImgID)
  Protected ImgHeight = ImageHeight(ImgID)
  Protected ImgID_1, ImgID_2
  
  If IsKeyPressed(#VK_SHIFT)
    deltaX * 5
    deltaY * 5
  EndIf
  If IsKeyPressed(#VK_LCONTROL) Or IsKeyPressed(#VK_RCONTROL)
    deltaX * 10
    deltaY * 10
  EndIf
  
  ; Roll horizontally
  If deltaX <> 0
    If deltaX > 0 ; Roll left
      ImgID_1 = GrabImage(ImgID, #PB_Any, 0, 0, deltaX, ImgHeight)
      ImgID_2 = GrabImage(ImgID, #PB_Any, deltaX, 0, ImgWidth - deltaX, ImgHeight)
      If StartDrawing(ImageOutput(ImgID))
        DrawImage(ImageID(ImgID_2), 0, 0)
        DrawImage(ImageID(ImgID_1), ImgWidth - deltaX, 0)
        StopDrawing()
      EndIf
    Else ; Roll right
      deltaX = Abs(deltaX)
      ImgID_1 = GrabImage(ImgID, #PB_Any, ImgWidth - deltaX, 0, deltaX, ImgHeight)
      ImgID_2 = GrabImage(ImgID, #PB_Any, 0, 0, ImgWidth - deltaX, ImgHeight)
      If StartDrawing(ImageOutput(ImgID))
        DrawImage(ImageID(ImgID_1), 0, 0)
        DrawImage(ImageID(ImgID_2), deltaX, 0)
        StopDrawing()
      EndIf
    EndIf
    If ImgID_1 : FreeImage(ImgID_1) : EndIf
    If ImgID_2 : FreeImage(ImgID_2) : EndIf
  EndIf
  
  ; Roll vertically
  If deltaY <> 0
    If deltaY > 0 ; Roll up
      ImgID_1 = GrabImage(ImgID, #PB_Any, 0, 0, ImgWidth, deltaY)
      ImgID_2 = GrabImage(ImgID, #PB_Any, 0, deltaY, ImgWidth, ImgHeight - deltaY)
      If StartDrawing(ImageOutput(ImgID))
        DrawImage(ImageID(ImgID_2), 0, 0)
        DrawImage(ImageID(ImgID_1), 0, ImgHeight - deltaY)
        StopDrawing()
      EndIf
    Else ; Roll down
      deltaY = Abs(deltaY)
      ImgID_1 = GrabImage(ImgID, #PB_Any, 0, ImgHeight - deltaY, ImgWidth, deltaY)
      ImgID_2 = GrabImage(ImgID, #PB_Any, 0, 0, ImgWidth, ImgHeight - deltaY)
      If StartDrawing(ImageOutput(ImgID))
        DrawImage(ImageID(ImgID_1), 0, 0)
        DrawImage(ImageID(ImgID_2), 0, deltaY)
        StopDrawing()
      EndIf
    EndIf
    If ImgID_1 : FreeImage(ImgID_1) : EndIf
    If ImgID_2 : FreeImage(ImgID_2) : EndIf
  EndIf
EndProcedure

Procedure UpdateCanvas()
  If StartDrawing(CanvasOutput(0))
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    Box(0, 0, GadgetWidth(0), GadgetHeight(0), RGB(240, 240, 240))
    DrawImage(ImageID(ImgID), 0, 0, ImageWidth(ImgID) * ZoomFactor, ImageHeight(ImgID) * ZoomFactor)
    StopDrawing()
  EndIf
EndProcedure

OpenWindow(0, 0, 0, 800, 600, "Image Roller", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), #PB_Canvas_Keyboard)
ImgID = CreateImage(#PB_Any, GadgetWidth(0), GadgetHeight(0), 24, #White)

If StartDrawing(ImageOutput(ImgID))
  For i = 1 To 100
    Box(Random(ImageWidth(ImgID)-300), Random(ImageHeight(ImgID)-300), Random(300), Random(300), Random($FFFFFF))
    Circle(Random(ImageWidth(ImgID)-150), Random(ImageHeight(ImgID)-150), Random(300), Random($FFFFFF))
  Next
  StopDrawing()
EndIf

SetActiveGadget(0)

; Main event loop
Repeat
  Event = WindowEvent()
  
  Select Event
    Case #PB_Event_Gadget
      If EventGadget() = 0
        Select EventType()
          Case #PB_EventType_LeftButtonDown
            IsMouseDown = #True
            LastMouseX = GetGadgetAttribute(0, #PB_Canvas_MouseX)
            LastMouseY = GetGadgetAttribute(0, #PB_Canvas_MouseY)
            VelocityX = 0
            VelocityY = 0
            
          Case #PB_EventType_LeftButtonUp
            IsMouseDown = #False
            
          Case #PB_EventType_MouseMove
            If IsMouseDown
              CurrentMouseX = GetGadgetAttribute(0, #PB_Canvas_MouseX)
              CurrentMouseY = GetGadgetAttribute(0, #PB_Canvas_MouseY)
              
              deltaX = (LastMouseX - CurrentMouseX) / ZoomFactor
              deltaY = (LastMouseY - CurrentMouseY) / ZoomFactor
              
              If deltaX <> 0 Or deltaY <> 0
                RollImage(ImgID, deltaX, deltaY)
                UpdateCanvas()
                
                ; Update velocity
                CurrentTime = ElapsedMilliseconds()
                TimeElapsed = CurrentTime - LastUpdateTime
                If TimeElapsed > 0
                  VelocityX = deltaX / TimeElapsed * 1000
                  VelocityY = deltaY / TimeElapsed * 1000
                EndIf
                LastUpdateTime = CurrentTime
                
                LastMouseX = CurrentMouseX
                LastMouseY = CurrentMouseY
              EndIf
            EndIf
            
          Case #PB_EventType_MouseWheel
            OldZoomFactor = ZoomFactor
            ZoomFactor = ZoomFactor * (1 + GetGadgetAttribute(0, #PB_Canvas_WheelDelta) * 0.1)
            ZoomFactor = Max(0.1, Min(5, ZoomFactor))  ; Limit zoom between 0.1x and 5x
            
            If ZoomFactor <> OldZoomFactor
              UpdateCanvas()
            EndIf
            
          Case #PB_EventType_KeyDown
            key = GetGadgetAttribute(0, #PB_Canvas_Key)
            
            Select key
              Case #PB_Shortcut_Left, #PB_Shortcut_Pad4  : RollImage(ImgID, 10, 0)
              Case #PB_Shortcut_Right, #PB_Shortcut_Pad6 : RollImage(ImgID, -10, 0)
              Case #PB_Shortcut_Up, #PB_Shortcut_Pad8    : RollImage(ImgID, 0, 10)
              Case #PB_Shortcut_Down, #PB_Shortcut_Pad2  : RollImage(ImgID, 0, -10)
              Case #PB_Shortcut_Pad7 : RollImage(ImgID, 10, 10)
              Case #PB_Shortcut_Pad1 : RollImage(ImgID, 10, -10)
              Case #PB_Shortcut_Pad9 : RollImage(ImgID, -10, 10)
              Case #PB_Shortcut_Pad3 : RollImage(ImgID, -10, -10)
            EndSelect
            
            UpdateCanvas()
        EndSelect
      EndIf
      
    Case #PB_Event_Timer
      If Not IsMouseDown And (VelocityX <> 0 Or VelocityY <> 0)
        ; Apply deceleration
        VelocityX = VelocityX * 0.95
        VelocityY = VelocityY * 0.95
        
        ; Apply movement
        RollImage(ImgID, VelocityX * 0.016, VelocityY * 0.016)  ; Assuming 60 FPS (1/60 ≈ 0.016)
        UpdateCanvas()
        
        ; Stop if velocity is very low
        If Abs(VelocityX) < 0.1 And Abs(VelocityY) < 0.1
          VelocityX = 0
          VelocityY = 0
        EndIf
      EndIf
      
    Case 0  ; No event, update animation
      If Not IsMouseDown And (VelocityX <> 0 Or VelocityY <> 0)
        ; Apply deceleration
        VelocityX = VelocityX * 0.95
        VelocityY = VelocityY * 0.95
        
        ; Apply movement
        RollImage(ImgID, VelocityX * 0.016, VelocityY * 0.016)  ; Assuming 60 FPS (1/60 ≈ 0.016)
        UpdateCanvas()
        
        ; Stop if velocity is very low
        If Abs(VelocityX) < 0.1 And Abs(VelocityY) < 0.1
          VelocityX = 0
          VelocityY = 0
        EndIf
      EndIf
  EndSelect
  
Until Event = #PB_Event_CloseWindow

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 3:23 pm
by infratec
Something is wrong with #PB_Any ...

I get
[15:56:26] [ERROR] RollImage.pb (Zeile: 50)
[15:56:26] [ERROR] #Image Objektnummer ist sehr hoch (über 100000), sind Sie dazu sicher?
I had to replace #PB_Any with a fixed number.

PB 6.11 x86 on WIndows 10 ith ASM backend

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 3:27 pm
by Fred
Of course, you can't use a #PB_Any result on param2 or CopyImage() which needs a new id. It's even written in the doc: https://www.purebasic.com/documentation ... image.html

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 4:18 pm
by RASHAD
Hi dige this is RASHAD GPT again :D
1 - Create Container gadget as View port
2 - Create Image Gadget loaded with the full image inside the Container
3 - Create Track Bar Or Scroll Bar to move the image gadget by resizing it

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 5:43 pm
by Caronte3D
To properly display the panorama, you must use the 3D engine, map the image onto a sphere, and place the camera inside.

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 5:45 pm
by dige
RASHAD my friend! Thx for your support.
I guess your solution is for scrolling an Image.
In this case I need a „rolling“ fx. Its only
suitable for 360 degree panorama Images.pls try my code with the pano_360.jpg ☺️

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 5:51 pm
by dige
Caronte3D wrote: Wed Jun 26, 2024 5:43 pm To properly display the panorama, you must use the 3D engine, map the image onto a sphere, and place the camera inside.
That would be a great rotating endless view for a screensaver, for example. But unfortunately I don't have these 3d capabilities.

But in my case, I'll just move the image content in a rolling fashion. I want to change the view of the panorama.

Re: 2D: Faster way to roll an image?

Posted: Wed Jun 26, 2024 6:00 pm
by RASHAD
Sorry dige
I will test your code later then responding ( if I have any idea :lol: )

Re: 2D: Faster way to roll an image?

Posted: Thu Jun 27, 2024 10:52 am
by wilbert
dige wrote: Wed Jun 26, 2024 2:44 pm I have considered two options for this. Using DrawImage and using GrabImage to scroll the content.
GrabImage seems to be much more performant. But is it any faster? So far it still looks quite jerky.
A faster way should be to use DrawingBuffer() together with CopyMemory() / MoveMemory() so you don't need to create additional images.
But that still doesn't eliminate the jerkiness. I think that has to do with the CanvasGadget .

Re: 2D: Faster way to roll an image?

Posted: Thu Jun 27, 2024 10:54 am
by Fred
A sprite with a windowedscreen might be smoother

Re: 2D: Faster way to roll an image?

Posted: Thu Jun 27, 2024 11:42 am
by Caronte3D
dige wrote: Wed Jun 26, 2024 5:51 pm That would be a great rotating endless view for a screensaver, for example. But unfortunately I don't have these 3d capabilities.
If you convert the panorama type image to cubemap (you can do it online), you can use the example "EnvironmentMapping" on the examples folder of PureBasic.

Re: 2D: Faster way to roll an image?

Posted: Tue Jul 02, 2024 4:40 pm
by pf shadoko
the easiest way is to use 3d
(enter image path (line 7)

Code: Select all

InitEngine3D():InitSprite():InitKeyboard():InitMouse()

ExamineDesktops()
OpenWindow(0, 0,0, DesktopWidth(0)*0.8,DesktopHeight(0)*0.8, "CreateShader - [Esc] quit",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, WindowWidth(0), WindowHeight(0), 0, 0, 0)

image.s="C:\PureBasic-code\media\Pano-360.jpg"
If FileSize(image)<0:MessageRequester("!", "enter 360 panoramic image path (above)"):CallDebugger:EndIf
Add3DArchive(GetPathPart(image), #PB_3DArchive_FileSystem):Parse3DScripts()
LoadTexture(0,GetFilePart(image))

CreateCamera(0, 0, 0, 100, 100):MoveCamera(0,0,3,-6):CameraLookAt(0,0,0,0)
CreateMaterial(0,TextureID(0))
DisableMaterialLighting(0,1)
MaterialCullingMode(0,#PB_Material_AntiClockWiseCull)
MaterialFilteringMode(0,#PB_Material_Anisotropic)
CreateSphere(0,1000,64,64)
CreateEntity(0,MeshID(0),MaterialID(0))

Define.f MouseX,Mousey

Repeat
	While WindowEvent():Wend
	ExamineKeyboard()
	ExamineMouse()
	MouseX = -MouseDeltaX() *  0.05
  MouseY = -MouseDeltaY() *  0.05
	RotateCamera(0, MouseY, MouseX, 0, #PB_Relative)	
	RenderWorld()
	FlipBuffers()    
Until KeyboardReleased(#PB_Key_Escape) Or MouseButton(3)

Re: 2D: Faster way to roll an image?

Posted: Wed Jul 03, 2024 8:11 am
by Fred
Looks cool !