Blitz3D+ Command Reference

TFormImage image,a#,b#,c#,d#

Parameters

image - image to transform

a# - top-left matrix element; how much of the source x goes into the new x

b# - top-right matrix element; how much of the source y goes into the new x

c# - bottom-left matrix element; how much of the source x goes into the new y

d# - bottom-right matrix element; how much of the source y goes into the new y

Description

Reshapes an image with a 2x2 transformation matrix.

This is the general-purpose image warper that ScaleImage, ResizeImage and RotateImage are all built on. Every pixel of the source ends up at new_x = a*x + b*y and new_y = c*x + d*y, so the four numbers let you stretch, squash, mirror, shear and rotate in one call - or any combination of those at once. Scaling by 2 across is 1,0,0,1 with a=2; mirroring is a negative a; a rotation by d degrees is Cos(d),Sin(d),-Sin(d),Cos(d).

It is the tool for effects you cannot get by drawing alone: a fake perspective shadow that leans away from a light, a wobbling heat-haze sprite, an enemy that squashes when it lands, a mirrored version of a sprite sheet so you do not have to draw the left-facing frames by hand. Because the result is baked into an image you draw it later with an ordinary DrawImage, at full speed.

The big gotcha is that TFormImage changes the image in place and it is cumulative. Each call throws away the old pixels and builds a new, differently sized canvas from the transformed corners, so calling it every frame with a small rotation quickly turns your sprite to mush. Keep a pristine original loaded, take a CopyImage of it, and transform the copy. Every frame of an animstrip is transformed, and the image's handle is moved so the picture stays anchored where it was. If the image you are transforming happens to be the current drawing buffer, the runtime quietly switches the buffer back to the front buffer first.

A matrix that flattens the image to nothing - all four values zero, or any other combination whose determinant is zero - has no sensible inverse and will fail inside the transform, so keep at least one axis alive. Sampling quality is controlled by TFormFilter: smooth bilinear filtering is on by default, and turning it off gives you crisp nearest-neighbour pixels for a retro look.

See also: ScaleImage, ResizeImage, RotateImage, TFormFilter, CopyImage, DrawImage.

Example

; TFormImage Example
; ------------------

Graphics 640,480,0,2
SetBuffer BackBuffer()

; Six 2x2 matrices to try out. a and b are the top row, c and d the
; bottom row: new_x = a*x + b*y and new_y = c*x + d*y.
Dim ma#(6),mb#(6),mc#(6),md#(6),mtitle$(6)
StorePreset 1,1,0,0,1,"identity - no change"
StorePreset 2,2,0,0,1,"stretch wide"
StorePreset 3,0.5,0,0,0.5,"half size"
StorePreset 4,-1,0,0,1,"mirror horizontally"
StorePreset 5,1,0.4,0,1,"shear"
StorePreset 6,Cos(30),Sin(30),-Sin(30),Cos(30),"rotate 30 degrees"

; Keep a pristine original - TFormImage rewrites the image in place,
; so every preset is applied to a fresh copy of this one
original=LoadImage("media/b3dlogo.jpg")
ResizeImage original,200,98

preset=1
shown=0

While Not KeyDown(1)

    Cls

    ; Number keys 1 to 6 choose a matrix
    For k=2 To 7
        If KeyHit(k) Then preset=k-1
    Next

    If preset<>shown Then
        shown=preset
        If tformed<>0 Then FreeImage tformed
        tformed=CopyImage(original)
        ; The line this example is about
        TFormImage tformed,ma(shown),mb(shown),mc(shown),md(shown)
    End If

    Text 0,0,"1-6: pick a matrix   Esc: exit"
    Text 0,20,"TFormImage img,"+ma(shown)+","+mb(shown)+","+mc(shown)+","+md(shown)+"   ("+mtitle(shown)+")"

    Text 0,50,"Original 200x98"
    DrawImage original,20,70

    Text 0,190,"Result "+ImageWidth(tformed)+"x"+ImageHeight(tformed)+" - TFormImage resizes the image to fit the corners"
    DrawImage tformed,20,210

    Flip

Wend

End

Function StorePreset(index,a#,b#,c#,d#,title$)
    ma(index)=a
    mb(index)=b
    mc(index)=c
    md(index)=d
    mtitle(index)=title
End Function

Index