Request : TransformSprite() explanation for noob

Just starting out? Need help? Post your questions and find answers here.
User avatar
TazNormand
User
User
Posts: 27
Joined: Tue May 26, 2009 3:17 pm
Location: France

Request : TransformSprite() explanation for noob

Post by TazNormand »

Hi all

1st sorry for my bad english.

Is there anybody who can explain me with simple words how works the TransformSprite() function. What is the default parameters of this function, if i display a sprite, what are the default transformsprite parameters to display my sprite at his default aspect.

Please, give much samples as possible, and if in your examples, your used sin/cos funcs, tell me why.

Thanks by advance

kind regards
User avatar
TazNormand
User
User
Posts: 27
Joined: Tue May 26, 2009 3:17 pm
Location: France

Re: Request : TransformSprite() explanation for noob

Post by TazNormand »

46 read, no reply, does nobody knows how works TransformSprite(), even Fred nor Freak ?
GPI
PureBasic Expert
PureBasic Expert
Posts: 1394
Joined: Fri Apr 25, 2003 6:41 pm

Re: Request : TransformSprite() explanation for noob

Post by GPI »

A normal sprite is a box with a given width and height. When you draw a sprite to a x/y-cordinate on screen.

With Transform sprite you can deform the box in any kind, for example a trapezium. But you must give coordinates of every corner. You can even rotate a sprite with this function (and maybe because of this sin & cos are used).

Important - the order of the corner is importet or it will be empty.

A little code to play with:

Code: Select all

If InitSprite() = 0 Or InitKeyboard() = 0
  MessageRequester("Error", "Sprite system can't be initialized", 0)
  End
EndIf

;
; Now, open windowed 800*600 screen
;
OpenWindow(0,0,0,800,600,"ESC=End",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
If OpenWindowedScreen(WindowID(0),0,0,800, 600)

  ; Load our 16 bit sprite (which is a 24 bit picture in fact, as BMP doesn't support 16 bit format)
  ; 
  LoadSprite(0, #PB_Compiler_Home + "examples/sources/Data/PureBasic.bmp")
  LoadSprite(1, #PB_Compiler_Home +"examples/sources/Data/Background.bmp")

  Dim x(3)
  Dim y(3)
  Dim dx(3)
  Dim dy(3)
  
  
  ;set random corner
  For i=0 To 3
    x(i)=Random(700,100)
    y(i)=Random(500,100)
    dx(i)=Random(3,1)
    dy(i)=Random(3,1)    
  Next  
    
  Repeat
    
    ; Inverse the buffers (the back become the front (visible)... And we can do the rendering on the back)
    
    FlipBuffers()
    
    ClearScreen(RGB(0,0,0))
    
    
    
    ;move corners randomly
    For i=0 To 3
      x(i)+dx(i)
      y(i)+dy(i)
      If x(i)<0
        x(i)=0:dx(i)=Random(3,1)
      EndIf
      If y(i)<0
        y(i)=0:dy(i)=Random(3,1)
      EndIf
      If x(i)>800
        x(i)=800:dx(i)=-Random(3,1)
      EndIf
      If y(i)>600
        y(i)=600:dy(i)=-Random(3,1)
      EndIf
      Debug " "+i+" "+x(i)+" "+y(i)
    Next
    
    
    ;transform
    TransformSprite(0,x(0),y(0),x(1),y(1),x(2),y(2),x(3),y(3))    
    ;draw to 0,0 - because the coordinates are in the transformation!
    DisplaySprite(0,0,0)
    
    ;transform Backside - uncommend this lines to see the diffrence    
    ;TransformSprite(1,x(0),y(0),x(3),y(3),x(2),y(2),x(1),y(1))    
    ;DisplaySprite(1,0,0)
    
    
    StartDrawing(ScreenOutput())
    For i=0 To 3
      DrawText(x(i),y(i),Str(i))
    Next
  
    
    LineXY(x(0),y(0),x(1),y(1))
    LineXY(x(1),y(1),x(2),y(2))
    LineXY(x(2),y(2),x(3),y(3))
    LineXY(x(3),y(3),x(0),y(0))
    StopDrawing()
    
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Escape) Or WindowEvent()=#PB_Event_CloseWindow
  
Else
  MessageRequester("Error", "Can't open a 800*600 - 32 bit screen !", 0)
EndIf

User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Request : TransformSprite() explanation for noob

Post by Demivec »

Here's something to play around with. I originally wrote it to demonstrate transforming a rectangular sprite for use in displaying isometric maps.

I updated it to show common transformations as well. I also added a feature to let you transform a sprite in real-time.

It does not deal with any 'Z' coordinates in the transformations.

Code: Select all

;Program description: Sprite transformation effects
;Author: Demivec
;Written for: Originally for PB 4.61, with Windows OS, may not function correctly for other OS.
;             It does not function correctly with the OpenGL subsystem.
;Date Written: 2 July 2012
;Last Updated: 4 October 2015 for PB 5.40b8 and added some additional features.
;

EnableExplicit
; Structure Point
;   x.i
;   y.i
; EndStructure

Structure Point_f
  x.f
  y.f
EndStructure

Enumeration sprites
  #spr_pb
  #spr_corner
  #spr_text_1
  #spr_text_2
  #spr_text_3
  #spr_text_4
  #spr_mousePointer
EndEnumeration

Enumeration fonts
  #font_large
  #font_small
EndEnumeration

Enumeration windows
  #win_main  
EndEnumeration

Procedure handleError(value, text.s = "Unknown Error.")
  If value = 0
    MessageRequester("Error", text)
    End
  EndIf
EndProcedure

;Sprite info: (width, height) = original dimensions, (newWidth, newHeight) = zoom dimensions,
; degree = rotation amount, (cx,cy) = center point for rotation
Procedure MakeSpriteTransformation(spriteID, width, height, cx, cy, degree, newWidth, newHeight)
  Protected.Point_f p1, p2, p3, p4
  Protected.f wf = width / newWidth, hf = height / newHeight
  
  If degree = 0
    ;simple transformation: no rotation, only zooming and translation movements possible 
    p1\x = ((       -cx) / wf) - 0.5: p1\y = ((        -cy) / hf) - 0.5
    p2\x = ((width - cx) / wf) - 0.5: p2\y = ((        -cy) / hf) - 0.5
    p3\x = ((width - cx) / wf) - 0.5: p3\y = ((height - cy) / hf) - 0.5
    p4\x = ((       -cx) / wf) - 0.5: p4\y = ((height - cy) / hf) - 0.5
    
  Else
    ;more complex transformation: rotation (around point cx,cy) and zooming possible 
    Protected.f angCos = Cos(Radian(degree)), angSin = Sin(Radian(degree))
    Protected.f v1, v2, v3, v4, v5, v6, v7, v8
    
    v1 = -cx * angCos: v3 = -cy * angSin
    v2 = -cx * angSin: v4 = -cy * angCos
    
    v6 = (width - cx) * angCos: v7 = (height - cy) * angSin
    v5 = (width - cx) * angSin: v8 = (height - cy) * angCos
     
    p1\x = ((v1 - v3) / wf) - 0.5: p1\y = ((v4 + v2) / hf) - 0.5
    p2\x = ((v6 - v3) / wf) - 0.5: p2\y = ((v4 + v5) / hf) - 0.5
    p3\x = ((v6 - v7) / wf) - 0.5: p3\y = ((v8 + v5) / hf) - 0.5
    p4\x = ((v1 - v7) / wf) - 0.5: p4\y = ((v8 + v2) / hf) - 0.5
  EndIf  
  
  TransformSprite(spriteID, p1\x, p1\y, p2\x, p2\y,  p3\x, p3\y,  p4\x, p4\y)
EndProcedure

;iso (squish) rotated clockwise degrees
Procedure MakeSpriteIsoClockwise(spriteID, width, height, cx, cy, degree, newWidth, newHeight)
  MakeSpriteTransformation(spriteID, width, height, cx, cy, degree, newWidth, newHeight)
EndProcedure

;iso (squish) rotated counter-clockwise degrees
Procedure  MakeSpriteIsoCounterClockwise(spriteID, width, height, cx, cy, degree, newWidth, newHeight)
  MakeSpriteTransformation(spriteID, width, height, cx, cy, 360 - degree, newWidth, newHeight)
EndProcedure  

Procedure MakeSpriteRotate(SpriteID, cx, cy, degree)
  Protected width = SpriteWidth(SpriteID), height = SpriteHeight(SpriteID)
  ZoomSprite(SpriteID, #PB_Default, #PB_Default)
  MakeSpriteTransformation(spriteID, width, height, cx, cy, degree, width, height)
EndProcedure

Procedure MakeSpriteZoomHorizontal(SpriteID, cx, cy, newWidth)
  Protected width = SpriteWidth(SpriteID), height = SpriteHeight(SpriteID)
  ZoomSprite(SpriteID, #PB_Default, #PB_Default)
  MakeSpriteTransformation(spriteID, width, height, cx, cy, 0, newWidth, height)
EndProcedure

Procedure MakeSpriteZoomVertical(SpriteID, cx, cy, newHeight)
  Protected width = SpriteWidth(SpriteID), height = SpriteHeight(SpriteID)
  ZoomSprite(SpriteID, #PB_Default, #PB_Default)
  MakeSpriteTransformation(spriteID, width, height, cx, cy, 0, width, newHeight)
EndProcedure

Procedure MakeSpriteNormal(SpriteID, cx = 0, cy = 0)
  Protected width = SpriteWidth(SpriteID), height = SpriteHeight(SpriteID)
  ZoomSprite(SpriteID, #PB_Default, #PB_Default)
  MakeSpriteTransformation(spriteID, width, height, cx, cy, 0, width, height)
EndProcedure


handleError(InitSprite(), "Can't open screen & sprite enviroment.")
handleError(InitMouse(), "Can't initialize mouse handler.")
handleError(InitKeyboard(), "Can't initialize keyboard handler.")
handleError(OpenWindow(#win_main, 0, 0, 800, 600, "Sprite Transformations, drag numbered corners to transform",
                       #PB_Window_SystemMenu | #PB_Window_ScreenCentered), "Can't open window.")
handleError(OpenWindowedScreen(WindowID(#win_main), 0, 0, 800, 600, 0, 0, 0), "Can't open windowed screen.")

handleError(LoadFont(#font_large, "Arial", 36), "Unable to load font.")
handleError(LoadFont(#font_small, "Arial", 8), "Unable to load font.")
handleError(CreateSprite(#spr_pb, 64, 64), "Sprite creation failed.")
handleError(StartDrawing(SpriteOutput(#spr_pb)), "Can't draw on sprite.")
  Box(0,0,64,64,RGB($FF,$FF,$00))
  DrawingMode(#PB_2DDrawing_Outlined)
  DrawingFont(FontID(#font_large))
  DrawText(0,0,"PB",RGB($FF,$00,$00))
  Box(0,0,64,64,RGB($00,$00,$FF))
  LineXY( 0,0,64,64,RGB($00,$00,$FF))
  LineXY(64,0, 0,64,RGB($00,$00,$FF))
StopDrawing()

handleError(CreateSprite(#spr_mousePointer, 8, 8, #PB_Sprite_AlphaBlending), "Sprite creation failed.")
handleError(StartDrawing(SpriteOutput(#spr_mousePointer)), "Can't draw on sprite.")
  FrontColor(RGB($00,$FF,$FF))
  LineXY(0,0, OutputWidth() - 1,OutputHeight() - 1)
  LineXY(0,0, 0,OutputHeight() - 3)
  LineXY(0,0, OutputWidth() - 3,0)
StopDrawing()
TransparentSpriteColor(#spr_mousePointer, RGB($00,$00,$00))
  

handleError(CreateSprite(#spr_corner, 8, 8, #PB_Sprite_AlphaBlending), "Sprite creation failed.")
handleError(StartDrawing(SpriteOutput(#spr_corner)), "Can't draw on sprite.")
  Box(0, 0, OutputWidth(), OutputHeight(), RGB($00, $FF, $00))
StopDrawing()

DataSection
  cornerCoordinates:
  Data.i 0,0, 64,0, 64,64, 0,64
EndDataSection

Dim corner.Point(3)
Define customSpritePosX = 400, customSpritePosY = 400, i
Restore cornerCoordinates
For i = 0 To 3
  handleError(CreateSprite(#spr_text_1 + i, 8, 16, #PB_Sprite_AlphaBlending), "Sprite creation failed.")
  handleError(StartDrawing(SpriteOutput(#spr_text_1 + i)), "Can't draw on sprite.")
    DrawingMode(#PB_2DDrawing_Outlined)
    DrawingFont(FontID(#font_small))
    DrawText(0, 0, Str(i + 1),RGB($FF,$FF,$FF),RGB($00,$00,$00))
  StopDrawing()
  TransparentSpriteColor(#spr_text_1 + i, RGB($00,$00,$00))
  Read.i corner(i)\x: corner(i)\x + customSpritePosX
  Read.i corner(i)\y: corner(i)\y + customSpritePosY
Next
  
Define direction = 2
Define zoomX     = 64
Define zoomY     = 64
Define angle, newWidth, newHeight, displayRow, event, i

ReleaseMouse(1)
Define mouseIsReleased = #True, dragCorner = -1
Repeat
  Repeat
    event = WindowEvent()
    Select event 
      Case #PB_Event_CloseWindow
        End 
    EndSelect
  Until event = 0
    
  FlipBuffers() 
  ClearScreen(RGB($40, $40, $40))
  
  displayRow = 70
  MakeSpriteNormal(#spr_pb, 32, 32) ;normal appearance
  DisplaySprite(#spr_pb, 100, displayRow) ;location is needed because display location was not part of transformation
  
  MakeSpriteRotate(#spr_pb, 32, 32, angle) ;rotate around center
  DisplaySprite(#spr_pb, 200, displayRow)
  MakeSpriteRotate(#spr_pb, 16, 16, angle) ;rotate around non-center point
  DisplaySprite(#spr_pb, 350, displayRow)
  newWidth = zoomX: newHeight = zoomX
  MakeSpriteZoomHorizontal(#spr_pb, 32, 32, newWidth) ;zoom horizontally
  DisplaySprite(#spr_pb, 500, displayRow)
  MakeSpriteZoomVertical(#spr_pb, 32, 32, newHeight) ;zoom vertically
  DisplaySprite(#spr_pb, 600, displayRow)
  
  displayRow = 280
  MakeSpriteIsoCounterClockwise(#spr_pb, 64, 64, 32, 32, angle, 64, 32) ;squished vertically
  DisplaySprite(#spr_pb, 200 - zoomX * 0.5, displayRow - zoomY * 0.5)
  MakeSpriteIsoCounterClockwise(#spr_pb, 64, 64, 32, 32, angle, 32, 64) ;squished horizontally
  DisplaySprite(#spr_pb, 300 - zoomX * 0.5, displayRow - zoomY * 0.5)
  
  MakeSpriteIsoClockwise(#spr_pb, 64, 64, 32, 32, angle, 2 * zoomX, 1 * zoomX) ;squished vertically and zoomed
  DisplaySprite(#spr_pb, 700 - zoomX * 0.5, displayRow - zoomY * 0.5)
  MakeSpriteIsoClockwise(#spr_pb, 64, 64, 32, 32, angle, 1 * zoomX, 2 * zoomX) ;squished horizontally and zoomed
  DisplaySprite(#spr_pb, 500 - zoomX * 0.5, displayRow - zoomY * 0.5)
  
  displayRow = 400
  MakeSpriteIsoCounterClockwise(#spr_pb, 64, 64, 32, 32, angle, 64, 20 + zoomX / 2) ;squishiness varying vertically
  DisplaySprite(#spr_pb, 100, displayRow)
  MakeSpriteIsoCounterClockwise(#spr_pb, 64, 64, 32, 32, angle, 20 + zoomX / 2, 64) ;squishiness varying horizontally
  DisplaySprite(#spr_pb, 200, displayRow)
  
 
  ExamineMouse()
  
  ;handle screen mouse activation/deactivation
  If MouseX() < 2 Or MouseX() > ScreenWidth() - 3 Or MouseY() < 2 Or MouseY() > ScreenHeight() -3
    ReleaseMouse(1): mouseIsReleased = #True
  EndIf
  
  If WindowMouseX(#win_main) >= 2 And
         WindowMouseX(#win_main) < WindowWidth(#win_main, #PB_Window_InnerCoordinate) - 2 And
         WindowMouseY(#win_main) >= 2 And
         WindowMouseY(#win_main) < WindowHeight(#win_main, #PB_Window_InnerCoordinate) - 2
    ReleaseMouse(0): mouseIsReleased = #False
    MouseLocate(WindowMouseX(#win_main), WindowMouseY(#win_main))
  EndIf
  
  ;handle corner dragging for deformable sprite
  If Not mouseIsReleased
    If MouseButton(#PB_MouseButton_Left)
      If dragCorner = -1
        For i = 0 To 3
          If SpriteCollision(#spr_corner, corner(i)\x, corner(i)\y, #spr_mousePointer, MouseX(), MouseY())
            dragCorner = i
            MouseDeltaX(): MouseDeltaY() ;reset these values for further reads
            Break
          EndIf
        Next
      Else
        corner(dragCorner)\x + MouseDeltaX(): corner(dragCorner)\y + MouseDeltaY()  
      EndIf
    ElseIf dragCorner <> -1
      corner(dragCorner)\x + MouseDeltaX(): corner(dragCorner)\y + MouseDeltaY()  
      dragCorner = -1 ;signal that no corner is being dragged      
    EndIf
  EndIf
  TransformSprite(#spr_pb, corner(0)\x,corner(0)\y, corner(1)\x,corner(1)\y, corner(2)\x,corner(2)\y, corner(3)\x,corner(3)\y)
  DisplaySprite(#spr_pb, 0, 0)  ;drawn at location 0,0 because sprite location is part of transformation
  
  ;display corners for dragging
  For i = 0 To 3
    DisplayTransparentSprite(#spr_corner, corner(i)\x, corner(i)\y, 128)
    DisplayTransparentSprite(#spr_text_1 + i, corner(i)\x + 8, corner(i)\y)
  Next
  If Not mouseIsReleased: DisplayTransparentSprite(#spr_mousePointer, MouseX(), MouseY()): EndIf
  
  ;update animation attributes
  angle + 1: If angle > 360: angle = 0: EndIf
  zoomX + direction

  If zoomX > 100  : direction = -2 : EndIf
  If zoomX < 20   : direction =  2 : EndIf
  
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Escape): Break: EndIf
  Delay(1)
ForEver
Post Reply