Infinite Image Zoom Flight [Windows only]

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Infinite Image Zoom Flight [Windows only]

Post by UEZ »

As dodicat would say: "I was inspired", here my inspiration to http://arkadia.xyz.

An Infinite zoom-in through the world of Arkadia flight.

Code: Select all

'coded by UEZ build 2018-01-09
'inspired by http://arkadia.xyz - thanks to by Nikolaus Baumgarten and Sophia Schomberg
'thanks to spudw2k for the mouse calculation

#define WIN_INCLUDEALL
#Include "fbgfx.bi"
#include "file.bi"
#Include "windows.bi"
#Include "win/gdiplus.bi"

Using GDIPLUS
Using FB

#Ifndef Floor
   #Define Floor(x) (((x) * 2.0 - 0.5) Shr 1) '' http://www.freebasic.net/forum/viewtopic.php?p=118633
   #Define Ceiling(x) (-((-(x) * 2.0 - 0.5) Shr 1))
#EndIf
  
declare function RemoteGetFile(url as string, filePath as string) as HRESULT
declare Sub DownloadImages()

DownloadImages() 'download images if not exist, code will end if download fails

Dim GDIPlusStartupInput As GDIPLUSSTARTUPINPUT 
Dim As ULONG_PTR GDIPlusToken 

GDIPlusStartupInput.GdiplusVersion = 1 
If (GdiplusStartup(@GDIPlusToken, @GDIPlusStartupInput, NULL) <> 0) Then 
   End 'FAILED TO INIT GDI+!
EndIf

Dim as any Ptr aImages(0 to 49), hImage
Dim as UByte i

'load local images with GDIPlus and convert it to GDI
For i = 0 to 48
   GdipLoadImageFromFile(CurDir & "\Images\Arkadia" & i & ".jpg", @hImage)
   GdipCreateHBITMAPFromBitmap(hImage, @aImages(i), &hFF000000)
   GdipDisposeImage(hImage)
Next

Dim As String sTitle = "GDI Infinite Image Zoom Flight v1.2"


'get desktop dimension
Dim As Integer iW_Dt, iH_Dt
ScreenInfo iW_Dt, iH_Dt

'image dimension
Const As Integer iW = 1200, iH = 900

ScreenControl FB.SET_DRIVER_NAME, "GDI"
ScreenRes iW_Dt, iH_Dt, 32, 1, GFX_HIGH_PRIORITY or GFX_FULLSCREEN or GFX_ALWAYS_ON_TOP
WindowTitle sTitle

Dim as HWND hHWND
ScreenControl(FB.GET_WINDOW_HANDLE, Cast(Integer, hHWND))

Dim As Any Ptr hDC = GetDC(hHWND), _
					hHBitmap = CreateCompatibleBitmap(hDC, iW_Dt, iH_Dt), _
					hDC_backbuffer = CreateCompatibleDC(hDC), _
               hMemDC = CreateCompatibleDC(hDC), hFont, DC_obj, hObjOld, hObjOld2

DC_obj = SelectObject(hDC_backbuffer, hHBitmap)

SetStretchBltMode(hDC_backbuffer, STRETCH_DELETESCANS)

hFont = CreateFontW(12, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, _
                    ANTIALIASED_QUALITY, DEFAULT_PITCH, "Arial")
hObjOld2 = SelectObject(hDC_backbuffer, hFont)
SetTextColor(hDC_backbuffer, &hFFFFFF)
SetBkMode(hDC_backbuffer, TRANSPARENT)


Dim evt As EVENT
Dim As ULong iFPS = 0
Dim as String sFPS = "0"
Dim As Double fTimer = Timer

'position FPS text
Dim tRECT as tagRECT
tRECT.Left = 4
tRECT.top = 4
tRECT.Right = 100
tRECT.Bottom = 20

Dim as any Ptr a(0 to 2)
Dim as Single b = 1.0, c, x, y, w, h, q, r, w2, h2
Dim as UByte e

w2 = iW_Dt / 2
h2 = iH_Dt / 2

If iW_Dt > 1.5 * iH_Dt Then
   q = iW_Dt
   r = 0.75 * iW_Dt
Else
   q = 1.5 * iH_Dt
   r = 0.75 * iH_Dt
EndIf

Dim as Single iStep = 0.025, iOutMin = 1, iOutMax = -1
Dim as UShort iInMin = 0, iInMax = iH_Dt
Dim As Integer iMPosX, iMPosY, iMPos

Do
   
   For e = 0 to 2
      a(e) = aImages((Floor(b) + e) Mod Ubound(aImages))
   Next
   
   c = 2^(Frac(b))
 
   For e = 0 to 2
      x = w2 - q / 2 * c
      y = h2 - r / 2 * c
      w = q * c
      h = r * c      
      hObjOld = SelectObject(hMemDC, a(e))
      StretchBlt(hDC_backbuffer, Floor(x), Floor(y), Floor(w), Floor(h), hMemDC, 0, 0, iW, iH, SRCCOPY)
      c *= 0.5
   Next
   
   iMPos = GetMouse (iMPosx, iMPosY)
    
   b += ((iMPosY - iInMin) * (iOutMax - iOutMin) / (iInMax - iInMin) + iOutMin) * iStep
   IF b < 0 Then b = UBound(aImages) - b
   
   DrawTextW(hDC_backbuffer, "FPS: " & sFPS, -1, @tRECT, 0)
   
   BitBlt(hDC, 0, 0, iW_Dt, iH_Dt, hDC_backbuffer, 0, 0, SRCCOPY)
   
   If Timer - fTimer > 0.99 Then
      sFPS = str(iFPS)
		iFPS = 0
		fTimer = Timer
	Else
		iFPS += 1
	EndIf
   
   'Sleep(1, 1)
Loop Until ((InKey = Chr(27)) Or (evt.Type = EVENT_WINDOW_CLOSE))

'Release resources
For i = 0 to 48
   DeleteObject(aImages(i))
Next
SelectObject(hDC_backbuffer, hObjOld2)
DeleteObject(hFont)
SelectObject(hMemDC, hObjOld)
DeleteDC(hMemDC)
SelectObject(hDC_backbuffer, DC_obj)
DeleteDC(hDC_backbuffer)
ReleaseDC(hHWND, hDC)
GdiplusShutdown(GDIPlusToken)



Sub DownloadImages()
   If FileExists(CurDir & "\Images") = 0 Then
      MkDir(CurDir & "\Images")
   End If
   Dim as UByte i
   For i = 0 to 48
      If FileExists(CurDir & "\Images\Arkadia" & i & ".jpg") = 0 Then
         ? "Downloading " & i + 1 & " / 49"
         If RemoteGetFile("http://arkadia.xyz/images/arkadia" & i & ".jpg", CurDir & "\Images\Arkadia" & i & ".jpg") < 0 Then End
      End If
   Next
End Sub

'https://www.freebasic.net/forum/viewtopic.php?f=6&t=24197&p=214027&hilit=URLDownloadToFile#p214324
function RemoteGetFile(url as string, filePath as string) as HRESULT '0 = success
   var hLib = Dylibload("urlmon.dll")
   if hLib = null then
      return -1
   end if

   dim pURLDownloadToFile as function _
       ( _
         byval as LPUNKNOWN, _
         byval as LPCSTR, _
         byval as LPCSTR, _
         byval as DWORD, _
         byval as LPBINDSTATUSCALLBACK _
       ) as HRESULT

   pURLDownloadToFile = Dylibsymbol( hLib, "URLDownloadToFileA" )
   if pURLDownloadToFile = null then
      dylibfree(hLib)
      return -2
   end if

   var result = pURLDownloadToFile(0, url, filePath, 0, 0)

   Dylibfree(hLib)
   return result
end function
The needed images will be downloaded and saved to current dir in folder images.

I used GDI because I don't know whether an equivalent FB function to StretchBlt is available - thus windows only.

The original web version is much smoother in zooming animation. GDI is unfortunately not.

Maybe someone has an idea...
Last edited by UEZ on Jan 09, 2018 13:25, edited 5 times in total.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Infinity Image Zoom Flight [Windows only]

Post by dodicat »

That is rather special UEZ.
FreeBASIC meets the big wide world.

Winapi coding is tricky but powerful.
Thank you.
I shall study your steps.
BasicCoder2
Posts: 3908
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Infinity Image Zoom Flight [Windows only]

Post by BasicCoder2 »

Looks good.
The algorithm appears to be this.
Keep enlarging the current image until it has doubled in size then replace it with the next image.
This example I presume will also run on Linux?
I had to load and save the 50 images as bitmaps for bload
The code uses D.J.Peters' multiput
Save this as multiput.bi

Code: Select all

' by D.J.Peters (Joshy)
' an put, scale, rotate hackfor the new ImageHeader format.
' MultiPut [destination],[xmidpos],[ymidpos],source,[xScale],[yScale],[Trans]

#define UseRad 'if not then Rotate are in degres

Sub MultiPut(Byval lpTarget As Any Ptr= 0, _
             Byval xMidPos  As Integer= 0, _
             Byval yMidPos  As Integer= 0, _
             Byval lpSource As Any Ptr   , _
             Byval xScale   As Single = 1, _
             Byval yScale   As Single = 1, _
             Byval Rotate   As Single = 0, _
             Byval Trans    As Integer= 0)

  If (screenptr=0) Or (lpSource=0) Then Exit Sub

  If xScale < 0.001 Then xScale=0.001
  If yScale < 0.001 Then yScale=0.001

  Dim As Integer MustLock,MustRotate

  If lpTarget= 0 Then MustLock  =1
  If Rotate  <>0 Then MustRotate=1

  Dim as Integer  TargetWidth,TargetHeight,TargetBytes,TargetPitch
  If MustLock Then
    ScreenInfo    _
    TargetWidth , _
    TargetHeight, _
    TargetBytes ,,_
    TargetPitch
    TargetBytes shr=3

    lpTarget=ScreenPtr
  Else
    TargetBytes  = cptr(uinteger Ptr,lpTarget)[1]
    TargetWidth  = cptr(uinteger Ptr,lpTarget)[2]
    TargetHeight = cptr(uinteger Ptr,lpTarget)[3]
    TargetPitch  = cptr(uinteger Ptr,lpTarget)[4]
    lpTarget    += 32
  End If
  If (TargetWidth<4) Or (TargetHeight<4) Then Exit Sub

  Dim As Integer   SourceWidth,SourceHeight,SourceBytes,SourcePitch
  if cptr(integer Ptr,lpSource)[0] = 7 then
    SourceBytes  = cptr(uinteger Ptr,lpSource)[1]
    SourceWidth  = cptr(uinteger Ptr,lpSource)[2]
    SourceHeight = cptr(uinteger Ptr,lpSource)[3]
    SourcePitch  = cptr(uinteger Ptr,lpSource)[4]
    lpSource    += 32
  else
    SourceBytes  = 1
    SourceWidth  = cptr(ushort Ptr,lpSource)[0] shr 3
    SourceHeight = cptr(ushort Ptr,lpSource)[1]
    SourcePitch  = SourceWidth
    lpSource    += 4
  end if
#if 0
  ? TargetWidth & "x" & TargetHeight & "x" & TargetBytes,TargetPitch
  ? SourceWidth & "x" & SourceHeight & "x" & SourceBytes,SourcePitch
  ? MustLock,Trans
  sleep:end 
#endif

  If (SourceWidth<2) Or (SourceHeight<2) Then Exit Sub
  If (TargetBytes<>SourceBytes) Then Exit Sub

#define xs 0 'screen
#define ys 1
#define xt 2 'texture
#define yt 3
  Dim As Single Points(3,3)
  points(0,xs)=-SourceWidth/2 * xScale
  points(1,xs)= SourceWidth/2 * xScale
  points(2,xs)= points(1,xs)
  points(3,xs)= points(0,xs)

  points(0,ys)=-SourceHeight/2 * yScale
  points(1,ys)= points(0,ys)
  points(2,ys)= SourceHeight/2 * yScale
  points(3,ys)= points(2,ys)

  points(1,xt)= SourceWidth-1
  points(2,xt)= points(1,xt)
  points(2,yt)= SourceHeight-1
  points(3,yt)= points(2,yt)

  Dim As Uinteger i
  Dim As Single x,y
  If MustRotate Then
    #ifndef UseRad
    Rotate*=0.017453292 'degre 2 rad
    #endif
    While Rotate< 0        :rotate+=6.2831853:Wend
    While Rotate>=6.2831853:rotate-=6.2831853:Wend
    For i=0 To 3
      x=points(i,xs)*Cos(Rotate) - points(i,ys)*Sin(Rotate)
      y=points(i,xs)*Sin(Rotate) + points(i,ys)*Cos(Rotate)
      points(i,xs)=x:points(i,ys)=y
    Next
  End If

  Dim As Integer yStart,yEnd,xStart,xEnd
  yStart=100000:yEnd=-yStart:xStart=yStart:xEnd=yEnd

#define LI 0   'LeftIndex
#define RI 1   'RightIndex
#define  IND 0 'Index
#define NIND 1 'NextIndex
  Dim As Integer CNS(1,1) 'Counters

  For i=0 To 3
    points(i,xs)=Int(points(i,xs)+xMidPos)
    points(i,ys)=Int(points(i,ys)+yMidPos)
    If points(i,ys)<yStart Then yStart=points(i,ys):CNS(LI,IND)=i
    If points(i,ys)>yEnd   Then yEnd  =points(i,ys)
    If points(i,xs)<xStart Then xStart=points(i,xs)
    If points(i,xs)>xEnd   Then xEnd  =points(i,xs)
  Next
  If yStart =yEnd         Then Exit Sub
  If yStart>=TargetHeight Then Exit Sub
  If yEnd   <0            Then Exit Sub
  If xStart = xEnd        Then Exit Sub
  If xStart>=TargetWidth  Then Exit Sub
  If xEnd   <0            Then Exit Sub

  Dim As uByte    Ptr t1,s1
  Dim As uShort   Ptr t2,s2
  Dim As uInteger Ptr t4,s4


#define ADD 0
#define CMP 1
#define SET 2
  Dim As Integer ACS(1,2) 'add compare and set
  ACS(LI,ADD)=-1:ACS(LI,CMP)=-1:ACS(LI,SET)=3
  ACS(RI,ADD)= 1:ACS(RI,CMP)= 4:ACS(RI,SET)=0

#define EX  0
#define EU  1
#define EV  2
#define EXS 3
#define EUS 4
#define EVS 5
  Dim As Single E(2,6),S(6),Length,uSlope,vSlope
  Dim As Integer U,UV,UA,UN,V,VV,VA,VN

  ' share the same highest point
  CNS(RI,IND)=CNS(LI,IND)
  If MustLock Then ScreenLock
  ' loop from Top to Bottom
  While yStart<yEnd
    'Scan Left and Right sides together
    For i=LI To RI
      ' bad to read but fast and short ;-)
      If yStart=points(CNS(i,IND),ys) Then
        CNS(i,NIND)=CNS(i,IND)+ACS(i,Add)
        If CNS(i,NIND)=ACS(i,CMP) Then CNS(i,NIND)=ACS(i,SET)
        While points(CNS(i,IND),ys) = points(CNS(i,NIND),ys)
          CNS(i, IND)=CNS(i,NIND)
          CNS(i,NIND)=CNS(i, IND)+ACS(i,Add)
          If CNS(i,NIND)=ACS(i,CMP) Then CNS(i,NIND)=ACS(i,SET)
        Wend
        E(i,EX) = points(CNS(i, IND),xs)
        E(i,EU) = points(CNS(i, IND),xt)
        E(i,EV) = points(CNS(i, IND),yt)
        Length  = points(CNS(i,NIND),ys)
        Length -= points(CNS(i, IND),ys)
        If Length <> 0.0 Then
          E(i,EXS) = points(CNS(i, NIND),xs)-E(i,EX):E(i,EXS)/=Length
          E(i,EUS) = points(CNS(i, NIND),xt)-E(i,EU):E(i,EUS)/=Length
          E(i,EVS) = points(CNS(i, NIND),yt)-E(i,EV):E(i,EVS)/=Length
        End If
        CNS(i,IND)=CNS(i,NIND)
      End If
    Next

    If (yStart<0)                              Then Goto SkipScanLine
    xStart=E(LI,EX)+0.5:If xStart>=TargetWidth Then Goto SkipScanLine
    xEnd  =E(RI,EX)-0.5:If xEnd  < 0           Then Goto SkipScanLine
    If (xStart=xEnd)                           Then Goto SkipScanLine
    'if xEnd  <xStart                           then goto SkipScanLine
    Length=xEnd-xStart
    uSlope=E(RI,EU)-E(LI,EU):uSlope/=Length
    vSlope=E(RI,EV)-E(LI,EV):vSlope/=Length
    If xstart<0 Then
      Length=Abs(xStart)
      U=Int(E(LI,EU)+uSlope*Length)
      V=Int(E(LI,EV)+vSlope*Length)
      xStart = 0
    Else
      U=Int(E(LI,EU)):V=Int(E(LI,EV))
    End If
    If xEnd>=TargetWidth Then xEnd=TargetWidth-1
    UV=Int(uSlope):UA=(uSlope-UV)*100000:UN=0
    VV=Int(vSlope):VA=(vSlope-VV)*100000:VN=0
    xEnd-=xStart
    Select Case TargetBytes
      Case 1
        t1=cptr(ubyte ptr,lpTarget)
        t1+=yStart*TargetPitch+xStart:xStart=0
        If Trans=0 Then
          While xStart<xEnd
            s1=lpSource+V*SourcePitch+U
            *t1=*s1
            U+=UV:UN+=UA:If UN>=100000 Then U+=1:UN-=100000
            V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000
            If u<0 Then u=0
            If v<0 Then v=0
            xStart+=1:t1+=1
          Wend
        Else
          While xStart<xEnd
            s1=lpSource+V*SourcePitch+U
            If *s1 Then *t1=*s1
            U+=UV:UN+=UA:If UN>=100000 Then U+=1:UN-=100000
            V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000
            If u<0 Then u=0
            If v<0 Then v=0
            xStart+=1:t1+=1
          Wend
        End If
      Case 2
        t2=cptr(Short Ptr,lpTarget)
        t2+=yStart*(TargetPitch shr 1)+xStart:xStart=0
        If Trans=0 Then
          While xStart<xEnd
            s2=cptr(Short Ptr,lpSource)+V*(SourcePitch shr 1)+U
            *t2=*s2
            U+=UV:UN+=UA:If UN>=100000 Then U+=1:UN-=100000
            V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000
            If u<0 Then u=0
            If v<0 Then v=0
            xStart+=1:t2+=1
          Wend
        Else
          While xStart<xEnd
            s2=cptr(Short Ptr,lpSource)+V*(SourcePitch shr 1)+U
            If *s2<>&HF81F Then *t2=*s2
            U+=UV:UN+=UA:If UN>=100000 Then U+=1:UN-=100000
            V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000
            If u<0 Then u=0
            If v<0 Then v=0
            xStart+=1:t2+=1
          Wend
        End If
      Case 4
        t4=cptr(Integer Ptr,lpTarget)+yStart*(TargetPitch shr 2)+xStart:xStart=0
        If Trans=0 Then
          While xStart<xEnd
            s4=cptr(Integer Ptr,lpSource)+V*(SourcePitch shr 2)+U
            *t4=*s4
            U+=UV:UN+=UA:If UN>=100000 Then U+=1:UN-=100000
            V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000
            If u<0 Then u=0
            If v<0 Then v=0
            xStart+=1:t4+=1
          Wend
        Else
          While xStart<xEnd
            's4=cptr(Integer Ptr,lpSource):s4+=V*(SourcePitch shr 2):s4+=U
            s4=cptr(Integer Ptr,lpSource)+V*(SourcePitch shr 2)+U
            If *s4<>&HFFFF00FF Then *t4=*s4
            U+=UV:UN+=UA:If UN>=100000 Then U+=1:UN-=100000
            V+=VV:VN+=VA:If VN>=100000 Then V+=1:VN-=100000
            If u<0 Then u=0
            If v<0 Then v=0
            xStart+=1:t4+=1
          Wend
        End If
    End Select

SkipScanLine:
    E(LI,EX)+=E(LI,EXS):E(LI,EU)+=E(LI,EUS):E(LI,EV)+=E(LI,EVS)
    E(RI,EX)+=E(RI,EXS):E(RI,EU)+=E(RI,EUS):E(RI,EV)+=E(RI,EVS)
    yStart+=1:If yStart=TargetHeight Then yStart=yEnd 'exit loop
  Wend
If MustLock Then ScreenUnlock
End Sub
And this is the demo code ...

Code: Select all

#include "multiput.bi"

'
' main
'
#define scr_w 600 'change it
#define scr_h 450

Dim As Any Ptr Sprite1,Sprite2
Dim As Single  xZoom1,yZoom1,Rotate,xZoom2,yZoom2
Dim As Integer x,y,b,counter
#define wh scr_w\2
#define hh scr_h\2

screenres scr_w,scr_h,32

Sprite1=ImageCreate(1200,900)
bload "C:/FreeBasic/misc2/Images/Arkadia0.bmp",Sprite1  'first image

xZoom1 = 1
yZoom1 = 1

dim as integer frame = 0
dim as string  fileName

do
      screenlock
      cls
      xZoom1 = xZoom1 + .01
      yZoom1 = yZoom1 + .01
      MultiPut(,wh,hh,Sprite1,xZoom1,yZoom1,0,1) ',1=trans
      locate 1,1
      print xZoom1
      screenunlock

      if xZoom1 > 2 then
        frame = frame + 1
        xZoom1 = 1
        yZoom1 = 1
        if frame = 49 then frame = 0
        fileName = "C:/FreeBasic/misc2/Images/Arkadia" & frame & ".bmp"
        bload fileName,Sprite1  'next image
      end if
      
      Sleep 10
loop until multikey(&H01)
Last edited by BasicCoder2 on Jan 06, 2018 22:44, edited 3 times in total.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Infinity Image Zoom Flight [Windows only]

Post by jj2007 »

Try fSpeed = 0.66666 ;-)
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Infinity Image Zoom Flight [Windows only]

Post by UEZ »

dodicat wrote:That is rather special UEZ.
FreeBASIC meets the big wide world.

Winapi coding is tricky but powerful.
Thank you.
I shall study your steps.
The WinAPI is powerful but for some effects very slow -> viewtopic.php?f=7&t=25669&p=232150#p232150

jj2007 wrote:Try fSpeed = 0.66666 ;-)
Warp speed through the "world". ^^
BasicCoder2 wrote:Looks good.
The algorithm appears to be this.
Keep enlarging the current image until it has doubled in size then replace it with the next image.
This example I presume will also run on Linux?
I had to load and save the 50 images as bitmaps for bload
Most of the code below is Joshy's multiput
[/code]
That's the algorithm. ;-) Thanks for Joshy's code.



I need to check whether I can make it smoother especially when the next image will be displayed. I cannot see any issue with the original web demo where an alpha blending is used.
BasicCoder2
Posts: 3908
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Infinity Image Zoom Flight [Windows only]

Post by BasicCoder2 »

The next question might be how do you make your own images?
This code generates 50 images. The images are of filled rectangles however you could fill the rectangles with artwork.
They are combined to produce 50 zoomable images.

Code: Select all

screenres 640,480,32
dim as integer x,y,px,py,start,ii,frame
x = 640
y = 480
dim as ulong c(50)
for i as integer = 0 to 49
  c(i) = rgb(int(rnd(1)*256),int(rnd(1)*256),int(rnd(1)*256))
next i

for start = 0 to 49 'draw and save 50 images 
  
  px = 0
  py = 0
  x = 640
  y = 480
  
  'draw first image out of 8 consective images
  for i as integer = start to start+7
    if i>29 then ii=i-20 else ii=i
    line (px,py)-(px+x,py+y),c(ii),bf
    px = px+x/4
    py = py+y/4
    x = x/2
    y = y/2
  next i
  bsave "zImage" & frame & ".bmp",0
  frame = frame + 1
  
  sleep
next start

sleep
Now we can zoom the images ...
Uses multiput.bi from the previous post

Code: Select all

#include "multiput.bi"

'
' main
'
#define scr_w 640 'change it
#define scr_h 480

Dim As Any Ptr imgZoom
Dim As Single  xZoom1,yZoom1,Rotate,xZoom2,yZoom2
Dim As Integer x,y,b,counter
#define wh scr_w\2
#define hh scr_h\2

screenres scr_w,scr_h,32

imgZoom=ImageCreate(640,480)
bload "zImage0.bmp",imgZoom  'first image

xZoom1 = 1
yZoom1 = 1

dim as integer frame = 0
dim as string  fileName

do
      screenlock
      cls
      xZoom1 = xZoom1 + .01
      yZoom1 = yZoom1 + .01
      MultiPut(,wh,hh,imgZoom,xZoom1,yZoom1,0,1) ',1=trans
      locate 1,1
      print frame
      screenunlock

      if xZoom1 > 2 then
        frame = frame + 1
        xZoom1 = 1
        yZoom1 = 1
        if frame = 49 then frame = 0
        fileName = "zImage" & frame & ".bmp"
        bload fileName,imgZoom  'next image
      end if
      
      Sleep 10
loop until multikey(&H01)
dafhi
Posts: 1645
Joined: Jun 04, 2005 9:51

Re: Infinite Image Zoom Flight [Windows only]

Post by dafhi »

UEZ wrote:The original web version is much smoother in zooming animation. GDI is unfortunately not.

Maybe someone has an idea...

Code: Select all

' roto zoom by dafhi
' update:  replaced int() with floor() for a 50% performance boost

' - explanation -

'imagine scaling an image so you can see big pixels.  (pixellated, not smooth-filter)
'now imagine overlaying a square equal to pixel size.  the square is never rotated,
'but the position is floating point and can move like an air hockey puck.

'this is the sampling square.

'the next part is to create the sampling grid.  if you want the image scaled down and rotated,
'the destination will have it's own x and y being perfect 1 increments, whereas the sampling
'grid will move in relatively large increments across the source

#Ifndef floor
#Define floor(x) (((x)*2.0-0.5)shr 1) '' http://www.freebasic.net/forum/viewtopic.php?p=118633
#define ceil(x) (-((-(x)*2.0-0.5)shr 1))
  #EndIf

#Ifndef UnionARGB
  Union UnionARGB
    As UInteger col
    Type: As UByte  B,G,R,A
    End Type
  End Union
#EndIf

Type sng2D
    As Single                     x,y
End Type

type imagevars '2017 Jan 7 - by dafhi
  as integer            w,h,bpp,bypp,pitch,rate,  wm, hm, pitchBy, num_pages, flags 'helpers
  as any ptr            im, pixels
  as ulong ptr          p32
  as string             driver_name
  declare sub           get_info(im as any ptr=0)
  as single             wh, hh, diagonal '2018 Jan 6
  declare sub           screen_init(w as integer=0, h as integer=0, bpp as integer=32, npages as integer=1, flags as integer=0)
  declare               destructor
                        '2017 Aug 17
  declare sub           create(w as integer=0, h as integer=0, col as ulong=&HFF000000)
  declare sub           blit(x as integer=0, y as integer=0, byref pdest as imagevars ptr=0, size as ubyte=0)
  declare sub           bmp_load( ByRef filename As String )
  Declare Sub                     SkewRect_ScaleRotate(ByVal scale_ As Single = 1.0, ByVal angle_ As Single = 0.0)
  Declare Sub                     SkewRect_Render(ByRef dest As imagevars ptr, _
    ByVal x As Integer = 0, _
    ByVal y As Integer = 0, _
    ByVal wid As Integer = -1, _
    ByVal hgt As Integer = -1)
 private:
  As sng2D              ptA,ptB,ptC,ptD
  declare sub           destroy
end type
Destructor.imagevars:  destroy
End Destructor
Sub imagevars.Destroy():  If ImageInfo(im) = 0 <> 0 Then ImageDestroy im: im = 0: endif:  End Sub
sub imagevars.get_info(im as any ptr)
  if im=0 then
    pixels=screenptr:  ScreenInfo w,h, bpp, bypp, pitch, rate, driver_name
  elseif Imageinfo(im)=0 then
    ImageInfo im, w, h, bypp, pitch, pixels
    bpp = bypp * 8:  this.im = im
  endif:  pitchBy=pitch\bypp
  wm=w-1: wh=w/2:  diagonal = sqr(w*w+h*h)
  hm=h-1: hh=h/2:  p32=pixels
end sub
sub imagevars.create(w as integer, h as integer, col as ulong)
  destroy:  get_info imagecreate(w,h,col)
End Sub
Sub imagevars.screen_init(w As integer, h As integer, _bpp as Integer, _pages as integer, _flags as integer)
  Destroy:  ScreenRes w,h,_bpp,_pages,_flags: get_info
  num_pages=_pages: flags=_flags:  if num_pages > 1 then screenset 0,1
End sub
sub imagevars.blit(x as integer, y as integer, byref pdest as imagevars ptr, size as ubyte) '2017 Aug 31
  if size>1 then
    var sizem=size-1:  dim as imagevars  dest
    if pdest=0 then dest.get_info: pdest=@dest
    var x1=x+wm*size: if x1>pdest->wm then x1=pdest->wm
    var y1=y+hm*size: if y1>pdest->hm then y1=pdest->hm
    for iy as long=y to y1 step size
      dim as ulong ptr psrc = p32 + ((iy-y)\size) * pitchBy
      if pdest=0 or pdest->im=0 then
        for ix as long=x to x1 step size
          line (ix,iy)-(ix+sizem,iy+sizem),psrc[(ix-x)\size],bf:  next
      else
        for ix as long=x to x1 step size
          line pdest->im,(ix,iy)-(ix+sizem,iy+sizem),psrc[(ix-x)\size],bf:  next
      endif:  next
  else
    if pdest=0 then:  put (x,y), im, pset
    else:  put pdest->im, (x,y), im, pset
  endif:  endif
End Sub
#Macro ClipVars()
  Dim As Integer  clipLeft,clipTop,xLeft=int(x+.5),yTop=int(y+.5)
 
  If x < 0 Then clipLeft = -x: xLeft = 0
  If y < 0 Then clipTop = -y: yTop = 0
 
  Dim As Integer  widM_ = wid_ - 1
  Dim As Integer  hgtM_ = hgt_ - 1
 
  Dim As Integer  xRight = xleft + widM_
  Dim As Integer  yBot = ytop + hgtM_
 
  If xRight > pDest->wM Then xRight = pDest->wM
  If yBot > pDest->hM Then yBot = pDest->hM
#EndMacro
Sub imagevars.SkewRect_ScaleRotate(ByVal scale_ As Single, ByVal angle_ As Single)
 
  If scale_ = 0 Then Exit Sub
  scale_ = 1 / scale_
 
  Dim As Single xLeft = wh * -scale_
  Dim As Single xRight = wh * scale_
  Dim As Single yTop = hh * -scale_
  Dim As Single yBot = hh * scale_
  Dim As Single cos_ = Cos( -angle_ )
  Dim As single sin_ = Sin( -angle_ )
  Dim As Single tmpA,tmpB
 
  #Macro Rot8_Trans(init_a,init_b,dsta, dstb)
     dsta = init_a
     dstb = init_b
     tmpA = cos_ * dsta + sin_ * dstb
     tmpB = cos_ * dstb - sin_ * dsta
     dsta = tmpA + wh + .5
     dstb = tmpB + hh + .5
  #EndMacro
 
  Rot8_Trans( xLeft, yTop, ptA.x, ptA.y )
  Rot8_Trans( xRight, yTop, ptB.x, ptB.y )
  Rot8_Trans( xLeft, yBot, ptC.x, ptC.y )
  Rot8_Trans( xRight, yBot, ptD.x, ptD.y )
 
End Sub
Sub imagevars.SkewRect_Render(ByRef pDest As imagevars ptr, _
  ByVal x As Integer, ByVal y As Integer, _
  ByVal wid_ As Integer, ByVal hgt_ As Integer)
 
  #Macro InterpolatePoint(dest_,from_,to_)
    dest_.x = from_.x + lerp * (to_.x - from_.x)
    dest_.y = from_.y + lerp * (to_.y - from_.y)
  #EndMacro
 
  #Macro LayerSource_Components(aa_mul1, aa_mul2)
    aa_fractional = aa_mul1 * aa_mul2
    sRed += aa_fractional * ptrSource->R
    sGrn += aa_fractional * ptrSource->G
    sBlu += aa_fractional * ptrSource->B
  #EndMacro
 
  #Macro BoundsCheckSource(aa_mul1, aa_mul2)
    If srcY >= 0 Then
      If srcX >= 0 Then
        If srcY < h Then
          If srcX < w Then
            LayerSource_Components( aa_mul1, aa_mul2 )
          EndIf
        EndIf
      EndIf
    EndIf
  #EndMacro
 
  ClipVars()
 
  Dim As Single aa_fractional, xGridStep = 1 / widM_
 
  For yDest As Integer = yTop To yBot
 
    Dim As Integer  yGrid = yDest + ClipTop
   
    Dim As single     lerp = (yGrid - yTop) / hgtM_
    Dim As sng2D      ptAC, ptBD
    InterpolatePoint( ptAC, ptA, ptC )
    InterpolatePoint( ptBD, ptB, ptD )
   
    Dim As UnionARGB Ptr pixDest = pDest->pixels + yDest * pDest->pitch
   
    For xDest As Integer = xLeft To xRight
   
      Dim As Integer  xGrid = xDest + ClipLeft
   
      Dim As sng2D srcFloatPos
     
      lerp = (xGrid - xLeft) * xGridStep
     
      InterpolatePoint( srcFloatPos, ptAC, ptBD )
     
      Dim As Integer  srcX = floor(srcFloatPos.x)
      Dim As Integer  srcY = floor(srcFloatPos.y)
      Dim As Single   aa_Left = srcX + 1 - srcFloatPos.x
      Dim As Single   aa_Top = srcY + 1 - srcFloatPos.y
      Dim As Single   aa_Right = 1 - aa_Left
      Dim As Single   aa_Bot = 1 - aa_Top
     
      Dim As Single   sRed
      Dim As Single   sGrn
      Dim As Single   sBlu
     
      Dim As UnionARGB ptr ptrSource = pixels
      ptrSource += srcY * pitchBy + srcX
      BoundsCheckSource( aa_Left, aa_Top ) ''A
     
      srcX += 1
      ptrSource += 1
      BoundsCheckSource( aa_Right, aa_Top ) ''B
     
      srcY += 1
      ptrSource += pitchBy
      BoundsCheckSource( aa_Right, aa_Bot ) ''D
     
      srcX -= 1
      ptrSource -= 1
      BoundsCheckSource( aa_Left, aa_Bot ) ''C

      pixDest[xDest].B = sBlu
      pixDest[xDest].G = sGrn
      pixDest[xDest].R = sRed

    Next
  Next
 
End Sub
sub imagevars.bmp_load( ByRef filename As String )  'modified fb example
  Dim As integer filenum = FreeFile(), w,h '2017 Sep 28
  for i as integer = 1 to 2
    If Open( filename For Binary Access Read As #filenum ) = 0 Then
      Get #filenum, 19, w
      Get #filenum, 23, h
      create w, abs(h)
      bload filename, im:  close #filenum: exit for
    endif
    Close #filenum
    filename = exepath & "\" & filename
  next
End sub
'
' ------ imagevars.bas


function round(in as single, places as ubyte = 2) as string
  dim as integer mul = 10 ^ places
  return str(csng(int(in * mul + .5) / mul))
End Function


sub Main
  dim as imagevars buf, im

  buf.screen_init 800,600
  
  ' ------ make some kind of texture
  im.create buf.w, buf.h
    
  var u = 49

  dim as ulong c(u+1)
  for i as integer = 0 to u
    c(i) = rgb(int(rnd(1)*256),int(rnd(1)*256),int(rnd(1)*256))
  next i

  dim as integer ii

  var px = 0f
  var py = 0f
  var x = csng(buf.w)
  var y = csng(buf.h)
   
  for i as integer = 0 to 7
    if i>29 then ii=i-20 else ii=i
    line im.im, (px,py)-(px+x,py+y),c(ii),bf
    px = px+x/4
    py = py+y/4
    x = x/2
    y = y/2
  next i
  ' ------ texture

  Dim As Single  xZoom1,yZoom1,xZoom2,yZoom2,angle=.1

  xZoom1 = .1
  yZoom1 = .1

  do
      var t = timer
      screenlock
        line (0,0)-(buf.w,buf.h),rgb(127,135,94),bf
        xZoom1 = xZoom1 + .01
        yZoom1 = yZoom1 + .01
        im.SkewRect_ScaleRotate( sqr(xzoom1^2+yzoom1^2), angle )
        im.SkewRect_Render( @buf,0,0,buf.w,buf.h )
        locate 1,1
        print " bps: "; round(1/(timer-t))
      screenunlock
      Sleep 10
  loop until multikey(&H01)
end sub

Main
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Infinite Image Zoom Flight [Windows only]

Post by MrSwiss »

I'll have to repeat myself yet again, unfortunately: 32-bit Color --> always ULong
(to be usefull for both FBC versions: 32/64 bit)!

Therefore, the Union has to be:

Code: Select all

#Ifndef UnionARGB
  Union UnionARGB
    As ULong col
    Type: As UByte  B,G,R,A
    End Type
  End Union
#EndIf
Alternative: UInteger<32> (if you like it: "as long as possible")
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Infinite Image Zoom Flight [Windows only]

Post by UEZ »

Thanks dafhi but I cannot use your code directly as I've to rewrite the complete code. Apart from that I need to understand it first. ^^

Beside the zooming I mean also when the bitmap is displayed and then zoomed you cannot see that the bitmap is printed to the screen (web version) whereas in my version you will see it as the zoomed bitmap is blurred and the saved bitmap in memory is not.

If you want to speed it up just comment out the line

Code: Select all

SetStretchBltMode(hDC, STRETCH_HALFTONE) 'set display quality to high
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Infinite Image Zoom Flight [Windows only]

Post by dodicat »

My effort.

Using an image scaler.
The pictures are loaded as .jpg from the images folder.
Put this beside the images folder and run.
Please use -gen gas. otherwise -gen gcc must be optimised for speed
-O2 or -O3

Code: Select all


#if sizeof(integer)=8
#include "windows.bi"
#endif
#Include  "win/gdiplus.bi"
Declare Function setT       Alias "timeBeginPeriod"(As Ulong=1) As Long
Declare Function freeT      Alias "timeEndPeriod"  (As Ulong=1) As Long
type bar
    as single start,finish,variable
    as uinteger fillcol,rimcol
    end type

sub ShowBar(startx as integer,starty as integer,length as integer,thickness as integer,B as bar)
    #define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)
    var xpos=map(b.start,b.finish,b.variable,startx,(startx+length))
    line(startx,starty)-(xpos,starty+thickness),B.fillcol,bf
    line(startx-1,starty-1)-(startx+length+1,starty+thickness+1),b.rimcol,b
end sub
dim as bar z
z.start=0
z.finish=48
z.fillcol=rgb(200,100,0)
z.rimcol=rgb(200,200,200)


screenres 1200,900,32
'An idea from UEZ in another thread.
Function Pload(Picture as String,byref i as any ptr=0) as long
   Dim As uinteger TMP 
   GDIPLUS.GdiplusStartup(@TMP,@type<GDIPLUS.GDIPLUSSTARTUPINPUT>(1),0)
   Dim as any Ptr Img
   if GDIPLUS.GdipLoadImageFromFile(Picture,@Img)>0 then return 0
   Dim As Single w,h
   GDIPLUS.GdipGetImageDimension(Img,@w,@h)
   if w*h=0 then return 0
   Dim As GDIPLUS.BitmapData Pdata
   Dim As Rect R=Type(0,0,w-1,h-1)
   GDIPLUS.GdipBitmapLockBits(Img,Cast(Any Ptr,@R),GDIPLUS.ImageLockModeRead,PixelFormat32bppARGB,@Pdata)
   For y as long = 0 To h-1
      For x as long = 0 To w-1 
           pset i,(x,y),Cast(ulong Ptr,Pdata.Scan0)[y*w+x]
      Next
   Next
return w*h
End Function

sub getsize(picture as string,byref w as single,byref h as single) 'unused
    Dim As uinteger TMP 
   GDIPLUS.GdiplusStartup(@TMP,@type<GDIPLUS.GDIPLUSSTARTUPINPUT>(1),0)
   Dim as any Ptr Img
   if GDIPLUS.GdipLoadImageFromFile(Picture,@Img)>0 then exit sub
   GDIPLUS.GdipGetImageDimension(Img,@w,@h)
end sub

Function Regulate(Byval MyFps As long,Byref fps As long) As long
    Static As Double timervalue,_lastsleeptime,t3,frames
    frames+=1
    If (Timer-t3)>=1 Then t3=Timer:fps=frames:frames=0
    Var sleeptime=_lastsleeptime+((1/myfps)-Timer+timervalue)*1000
    If sleeptime<1 Then sleeptime=1
    _lastsleeptime=sleeptime
    timervalue=Timer
    Return sleeptime
End Function

function resize(im As Any Ptr,Wdth As Single,Hght as single) as any ptr
     #define putpixel(_x,_y,colour)    *cptr(ulong ptr,rowS+ (_y)*pitchS+ (_x) shl 2)  =(colour)
     #define _getpixel(_x,_y)           *cptr(ulong ptr,row + (_y)*pitch + (_x) shl 2)
     #define map(a,b,x,c,d) ((d)-(c))*((x)-(a))\((b)-(a))+(c)
    static As Integer pitch,pitchs
    static As Any Ptr row,rowS
    static As Ulong Ptr pixel,pixels
    static As Integer ddx,ddy,resultx,resulty
    Imageinfo im,ddx,ddy,,pitch,row
    dim as any ptr im2=imagecreate(Wdth,Hght)
    imageinfo im2,,,,pitchS,rowS
    For y As long=0 To Hght-1
         resulty=map(0,Hght,y,0,ddy)
        For x As long=0 To Wdth-1
            resultx=map(0,Wdth,x,0,ddx)
                    putpixel(x,y,_getpixel(resultx,resulty))
        Next x
    Next y
    return im2
End function

'text 
sub show(x as long,y as long,s as string,e as single=1,col as ulong,alph as ubyte=255)
    dim as any ptr i=imagecreate(8*len(s),16)
    draw string i,(0,0),s,col
    i=resize(i,e*8*len(s),e*16)
    put(x,y),i,alpha,alph
    imagedestroy i
    end sub


dim as string file="images/arkadia0.jpg" 


if Pload(file) =0  then print "unable to load":sleep:end 'TEST IF IMAGES ARE AVAILABLE.
show(500,300,"Please wait ...",2,rgb(255,255,255))
dim as integer w,h
screeninfo w,h

dim as any ptr im(0 to 48)
for n as long=0 to 48
    z.variable=n              'n always lies between start and finish
     ShowBar(500,350,200,10,z)
    im(n)=imagecreate(w,h)
file="images/arkadia"+str(n)+".jpg"
Pload(file,im(n))
next

dim as single x,y,number
dim as long fps,myfps
#define map(a,b,x,c,d) ((d)-(c))*((x)-(a))\((b)-(a))+(c)
do
    if (w+x)>=w*2 then number+=1:x=0:y=0  'doube scale
    number=number mod 49
 dim as any ptr tmp=resize(im(number),w+x,h+y)
    screenlock
    cls
put(-x\2,-y\2),tmp

show(600,300,"FPS  " &fps,2,rgb(255,255,255))
show(600,320,str(number) + " of 48",1,rgb(255,255,255))
screenunlock
x+=8
y+=8*.75
myfps=map(0,1200,x,13,25)
setT 
sleep  regulate(myfps,fps)
freeT
imagedestroy tmp
loop until len(inkey)
for n as long=0 to 48
    imagedestroy(im(n))
    next

sleep
 
I have tried a variable framerate.
Probably needs a bit tweaked.
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Infinite Image Zoom Flight [Windows only]

Post by UEZ »

I analysed the JS code and understood how the issue with switching to next images was solved -> very smart. I updated the code appropriately - check out post #1.

Btw, STRETCH_DELETESCANS produces also good quality images and is much faster than STRETCH_HALFTONE. FPS is increased extremely. :-)
Well, due to internal integer format of the GDI functions the screen is little bit wobbling.

@dodicat: thanks for effort. Very nice and informative to see how you solve this things by your own "style"!
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Infinite Image Zoom Flight [Windows only]

Post by jj2007 »

UEZ wrote:due to internal integer format of the GDI functions the screen is little bit wobbling.
Gdi+ has many float equivalents, you might check if one of them fits. DrawImage is a candidate: The image is scaled to fit the rectangle.
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Infinite Image Zoom Flight [Windows only]

Post by UEZ »

jj2007 wrote:
UEZ wrote:due to internal integer format of the GDI functions the screen is little bit wobbling.
Gdi+ has many float equivalents, you might check if one of them fits. DrawImage is a candidate: The image is scaled to fit the rectangle.
I know that but copying to the screen is much slower in GDI + than the GDI blitting. Anyway, I want to test also the GDI + version and if it is almost enough (against my expectations) I will publish it.

Edit: the GDI+ version runs @10 fps and wobbles, too. I didn't expect wobbling in GDI+. Hmmm...
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Infinite Image Zoom Flight [Windows only]

Post by jj2007 »

UEZ wrote:the GDI+ version runs @10 fps and wobbles, too. I didn't expect wobbling in GDI+. Hmmm...
Bad luck. Not that surprising, though, since even GDI+ has to convert the floats to integers at a certain point. You tested with aliasing on, I suppose?
UEZ
Posts: 988
Joined: May 05, 2017 19:59
Location: Germany

Re: Infinite Image Zoom Flight [Windows only]

Post by UEZ »

jj2007 wrote:
UEZ wrote:the GDI+ version runs @10 fps and wobbles, too. I didn't expect wobbling in GDI+. Hmmm...
Bad luck. Not that surprising, though, since even GDI+ has to convert the floats to integers at a certain point. You tested with aliasing on, I suppose?
No, there are usually two kind of same functions in the GDI+ lib. One is integer, the 2nd one is float. I used of course the float version. Further anti aliasing makes sense when you draw something with pens / brushes.

Anyhow, I figured out how to disable the wobbling also in GDI+ -> GdipSetInterpolationMode is the magic function.

Check it out:

Code: Select all

'coded by UEZ build 2018-01-09
'inspired by http://arkadia.xyz - thanks to by Nikolaus Baumgarten and Sophia Schomberg

#Define WIN_INCLUDEALL
#Include "fbgfx.bi"
#include "file.bi"
#Include "windows.bi"
#Include "win/gdiplus.bi"

Using GDIPLUS
Using FB

#Ifndef Floor
   #Define Floor(x) (((x) * 2.0 - 0.5) Shr 1) '' http://www.freebasic.net/forum/viewtopic.php?p=118633
   #Define Ceiling(x) (-((-(x) * 2.0 - 0.5) Shr 1))
#EndIf
  
declare function RemoteGetFile(url as string, filePath as string) as HRESULT
declare Sub DownloadImages()

DownloadImages() 'download images if not exist, code will end if download fails

Dim GDIPlusStartupInput As GDIPLUSSTARTUPINPUT 
Dim As ULONG_PTR GDIPlusToken 

GDIPlusStartupInput.GdiplusVersion = 1 
If (GdiplusStartup(@GDIPlusToken, @GDIPlusStartupInput, NULL) <> 0) Then 
   End 'FAILED TO INIT GDI+!
EndIf

Dim as any Ptr aImages(0 to 49), hImage
Dim as UByte i

'load local images with GDIPlus and convert it to GDI
For i = 0 to 48
   GdipLoadImageFromFile(CurDir & "\Images\Arkadia" & i & ".jpg", @aImages(i))
Next

Dim As String sTitle = "GDI+ Infinite Image Zoom Flight v1.2"


'get desktop dimension
Dim As Integer iW_Dt, iH_Dt
ScreenInfo iW_Dt, iH_Dt

'image dimension
Const As Integer iW = 1200, iH = 900

ScreenControl FB.SET_DRIVER_NAME, "GDI"
ScreenRes iW_Dt, iH_Dt, 24, 1, GFX_HIGH_PRIORITY or GFX_FULLSCREEN or GFX_ALWAYS_ON_TOP
WindowTitle sTitle

Dim as HWND hHWND
ScreenControl(FB.GET_WINDOW_HANDLE, Cast(Integer, hHWND))

Dim As Any Ptr hDC = GetDC(hHWND), _
					hHBitmap = CreateCompatibleBitmap(hDC, iW_Dt, iH_Dt), _
					hDC_backbuffer = CreateCompatibleDC(hDC), _
               hCanvas, hFont, DC_obj, hObjOld, hObjOld2

DC_obj = SelectObject(hDC_backbuffer, hHBitmap)
hFont = CreateFontW(12, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, _
                    ANTIALIASED_QUALITY, DEFAULT_PITCH, "Arial")
hObjOld2 = SelectObject(hDC_backbuffer, hFont)
SetTextColor(hDC_backbuffer, &hFFFFFF)
SetBkMode(hDC_backbuffer, TRANSPARENT)

GdipCreateFromHDC(hDC_backbuffer, @hCanvas)
GdipSetPixelOffsetMode(hCanvas, PixelOffsetModeHalf)
GdipSetInterpolationMode(hCanvas, InterpolationModeNearestNeighbor)

Dim evt As EVENT
Dim As ULong iFPS = 0
Dim as String sFPS = "0"
Dim As Double fTimer = Timer

'position FPS text
Dim tRECT as tagRECT
tRECT.Left = 4
tRECT.top = 4
tRECT.Right = 100
tRECT.Bottom = 20

Dim as any Ptr a(0 to 2)
Dim as Single b = 1.0, c, d, f, g, l, q, r, v, w
Dim as UByte e

v = iW_Dt / 2
w = iH_Dt / 2

If iW_Dt > 1.5 * iH_Dt Then
   q = iW_Dt
   r = 0.75 * iW_Dt
Else
   q = 1.5 * iH_Dt
   r = 0.75 * iH_Dt
EndIf

Dim as Single iStep = 0.05, iOutMin = 1.0, iOutMax = -1.0
Dim as UShort iInMin = 0, iInMax = iH_Dt
Dim As Integer iMPosX, iMPosY, iMPos

Do
   
   For e = 0 to 2
      a(e) = aImages((Floor(b) + e) Mod Ubound(aImages))
   Next
   
   c = 2^(Frac(b))
 
   For e = 0 to 2
      d = v - q / 2 * c
      f = w - r / 2 * c
      g = q * c
      l = r * c      
      GdipDrawImageRect(hCanvas, a(e), d, f, g, l)
      c *= 0.5
   Next
   
   iMPos = GetMouse (iMPosx, iMPosY)
   b += ((iMPosY - iInMin) * (iOutMax - iOutMin) / (iInMax - iInMin) + iOutMin) * iStep
   IF b < 0 Then b = UBound(aImages) - b
   
   DrawTextW(hDC_backbuffer, "FPS: " & sFPS, -1, @tRECT, 0)
   
   BitBlt(hDC, 0, 0, iW_Dt, iH_Dt, hDC_backbuffer, 0, 0, SRCCOPY)
   
   If Timer - fTimer > 0.99 Then
      sFPS = str(iFPS)
		iFPS = 0
		fTimer = Timer
	Else
		iFPS += 1
	EndIf
   
   'Sleep(1, 1)
Loop Until ((InKey = Chr(27)) Or (evt.Type = EVENT_WINDOW_CLOSE))

'Release resources
For i = 0 to 48
   GdipDisposeImage(aImages(i))
Next
SelectObject(hDC_backbuffer, hObjOld2)
DeleteObject(hFont)
SelectObject(hDC_backbuffer, DC_obj)
DeleteDC(hDC_backbuffer)
ReleaseDC(hHWND, hDC)
GdipDeleteGraphics(hCanvas)
GdiplusShutdown(GDIPlusToken)



Sub DownloadImages()
   If FileExists(CurDir & "\Images") = 0 Then
      MkDir(CurDir & "\Images")
   End If
   Dim as UByte i
   For i = 0 to 48
      If FileExists(CurDir & "\Images\Arkadia" & i & ".jpg") = 0 Then
         ? "Downloading " & i + 1 & " / 49"
         If RemoteGetFile("http://arkadia.xyz/images/arkadia" & i & ".jpg", CurDir & "\Images\Arkadia" & i & ".jpg") < 0 Then End
      End If
   Next
End Sub

'https://www.freebasic.net/forum/viewtopic.php?f=6&t=24197&p=214027&hilit=URLDownloadToFile#p214324
function RemoteGetFile(url as string, filePath as string) as HRESULT '0 = success
   var hLib = Dylibload("urlmon.dll")
   if hLib = null then
      return -1
   end if

   dim pURLDownloadToFile as function _
       ( _
         byval as LPUNKNOWN, _
         byval as LPCSTR, _
         byval as LPCSTR, _
         byval as DWORD, _
         byval as LPBINDSTATUSCALLBACK _
       ) as HRESULT

   pURLDownloadToFile = Dylibsymbol( hLib, "URLDownloadToFileA" )
   if pURLDownloadToFile = null then
      dylibfree(hLib)
      return -2
   end if

   var result = pURLDownloadToFile(0, url, filePath, 0, 0)

   Dylibfree(hLib)
   return result
end function
It runs at ~15 fps (1600x900 px).
Last edited by UEZ on Jan 09, 2018 12:53, edited 1 time in total.
Post Reply