AffineTransformEffectLib — Affine Transform Effect

Applies GPU-accelerated affine transformations (rotation, uniform scaling, center offset) to any visual control. The effect wraps FireMonkey’s TAffineTransformEffect and renders in real-time, making it ideal for image rotation controls, zoom effects, spinning animations, and interactive transform UIs. 18 functions.

CategoryCountDescription
Error Handling4affine_error, errormsg$, strerror$, clearerror
Creation & Destruction2affine# (create), affine_free (destroy)
Transform Properties8centerx, centery, rotation, scale (get/set)
Effect Control4enabled, trigger (get/set)
ⓘ Effect Ownership: The effect is owned by its parent control, not managed by garbage collection. Destroying the parent control also destroys the effect. Use affine_free only if you need to remove the effect while keeping the parent alive.

Cross-Platform Support

PlatformStatusNotes
Windows✅ Full SupportGPU-accelerated via Direct2D
Linux✅ Full SupportSoftware rendering fallback
Android✅ Full SupportGPU-accelerated

Error Handling

All functions set an error code on failure. Check with affine_error() after operations. Error code 0 means success.

FunctionSignatureDescription
affine_error()affine_error@Returns last error code (0 = no error)
affine_errormsg$()affine_errormsg$@Returns last error message as string
affine_strerror$(code)affine_strerror$@nConverts an error code to descriptive text
affine_clearerror()affine_clearerror@Clears the error state

Error Codes

CodeConstantMeaning
0ERR_NONENo error
1ERR_NIL_EFFECTEffect pointer is nil
2ERR_INVALID_EFFECTPointer is not a valid TAffineTransformEffect
3ERR_INVALID_VALUEProperty value out of range
4ERR_NIL_PARENTParent control pointer is nil
5ERR_INVALID_PARENTPointer is not a valid TFmxObject
╯ error-check.bas
let aff# = affine#(img#)
if affine_error() <> 0 then
    print "Error: " + affine_errormsg$()
else
    print "Effect created successfully"
endif

Creation & Destruction

FunctionSignatureDescription
affine#(parent#)affine#@#Creates an affine transform effect attached to the given control. Returns the effect pointer.
affine_free(effect#)affine_free@#Destroys the effect and removes it from the parent control.

The parent# can be any visual control: images, rectangles, panels, buttons, labels, shapes, etc. The effect is applied immediately upon creation with default values (no rotation, scale = 1.0, center at 0.5, 0.5).

╯ create-effect.bas
' Create effect on an image
let aff# = affine#(img#)

' Later, remove the effect
affine_free(aff#)

Transform Properties

Center Point

The center point defines the origin of rotation and scaling, expressed as normalized coordinates (0.0 to 1.0). Default is (0.5, 0.5) — the center of the control.

FunctionSignatureDescription
affine_centerx#(effect#, value)affine_centerx#@#nSets horizontal center (0.0 = left, 1.0 = right)
affine_centerx(effect#)affine_centerx@#Gets horizontal center
affine_centery#(effect#, value)affine_centery#@#nSets vertical center (0.0 = top, 1.0 = bottom)
affine_centery(effect#)affine_centery@#Gets vertical center
ValuePosition
0.0, 0.0Top-left corner
0.5, 0.5Center (default)
1.0, 1.0Bottom-right corner
0.0, 0.5Left edge, vertical center
1.0, 0.0Top-right corner
╯ center-point.bas
' Rotate around the top-left corner
affine_centerx#(aff#, 0.0)
affine_centery#(aff#, 0.0)
affine_rotation#(aff#, 45)

' Rotate around the center (default)
affine_centerx#(aff#, 0.5)
affine_centery#(aff#, 0.5)

Rotation

Sets the rotation angle in degrees. Positive values rotate clockwise. Any numeric value is accepted (including negative and values > 360°).

FunctionSignatureDescription
affine_rotation#(effect#, degrees)affine_rotation#@#nSets rotation angle in degrees
affine_rotation(effect#)affine_rotation@#Gets current rotation angle
╯ rotation.bas
affine_rotation#(aff#, 45)      ' 45 degrees clockwise
affine_rotation#(aff#, -30)     ' 30 degrees counter-clockwise
affine_rotation#(aff#, 720)     ' Two full rotations

let deg = affine_rotation(aff#)
print "Current rotation: " + str$(deg)

Scale

Uniform scale factor applied to the control. A value of 1.0 is the original size. Values less than 1.0 shrink; values greater than 1.0 enlarge.

FunctionSignatureDescription
affine_scale#(effect#, value)affine_scale#@#nSets uniform scale factor
affine_scale(effect#)affine_scale@#Gets current scale factor
ScaleEffect
0.2525% of original size
0.5Half size
1.0Original size (default)
1.5150% of original size
2.0Double size
╯ scale.bas
affine_scale#(aff#, 1.5)    ' Enlarge 50%
affine_scale#(aff#, 0.75)   ' Shrink to 75%

let s = affine_scale(aff#)
print "Current scale: " + str$(s)

Effect Control

Enabled

Toggles the effect on or off without destroying it. When disabled, the control renders as if the effect does not exist.

FunctionSignatureDescription
affine_enabled#(effect#, value)affine_enabled#@#nEnables (1) or disables (0) the effect
affine_enabled(effect#)affine_enabled@#Gets enabled state (1 = on, 0 = off)

Trigger

The trigger property is a string used by FireMonkey’s animation system. Setting it starts the effect’s animation (if any). Primarily used for integration with animation components.

FunctionSignatureDescription
affine_trigger#(effect#, trigger$)affine_trigger#@#$Sets trigger string
affine_trigger$(effect#)affine_trigger$@#Gets current trigger string
╯ toggle-effect.bas
' Disable the effect (control renders normally)
affine_enabled#(aff#, 0)

' Re-enable it
affine_enabled#(aff#, 1)

' Check state
if affine_enabled(aff#) = 1 then
    print "Effect is active"
endif

Complete Examples

Rotate an Image

Creates an image with a 15° rotation and slight scale-down applied as a visual effect.

╯ affine-rotate.bas
let frm# = Pointer#(0)
let img# = Pointer#(0)
let aff# = Pointer#(0)

frm# = form#("Affine Transform Demo", 400, 350)

img# = image#(frm#)
image_bounds#(img#, 100, 30, 200, 150)
image_load#(img#, "https://picsum.photos/200/150")

' Create affine transform effect
aff# = affine#(img#)
affine_rotation#(aff#, 15)   ' Rotate 15 degrees
affine_scale#(aff#, 0.9)     ' Scale down slightly

form_show(frm#)

Interactive Rotation Control

Uses a trackbar to interactively rotate an image from −180° to +180°.

╯ affine-rotation-control.bas
let frm# = Pointer#(0)
let img# = Pointer#(0)
let aff# = Pointer#(0)
let trkRot# = Pointer#(0)
let lblRot# = Pointer#(0)

frm# = form#("Rotation Control", 450, 400)

img# = image#(frm#)
image_bounds#(img#, 125, 30, 200, 150)
image_load#(img#, "https://picsum.photos/200/150")

aff# = affine#(img#)
affine_rotation#(aff#, 0)

' Rotation slider (-180 to 180)
lblRot# = label#(frm#, "Rotation: 0", 50, 200)
trkRot# = trackbar#(frm#)
trackbar_bounds#(trkRot#, 50, 230, 350, 30)
trackbar_max#(trkRot#, 360)
trackbar_value#(trkRot#, 180)
trackbar_onchange#(trkRot#, "OnRotChange")

form_show(frm#)

function OnRotChange(sender#) local deg
  let deg = trackbar_value(trkRot#) - 180
  affine_rotation#(aff#, deg)
  label_text#(lblRot#, "Rotation: " + str$(deg))
endfunction

Scale and Rotate Combined

Combines a fixed rotation with an interactive scale slider (0.5× to 2.0×).

╯ affine-scale-control.bas
let frm# = Pointer#(0)
let img# = Pointer#(0)
let aff# = Pointer#(0)
let trkScale# = Pointer#(0)
let lblScale# = Pointer#(0)

frm# = form#("Scale Control", 450, 400)

img# = image#(frm#)
image_bounds#(img#, 125, 30, 200, 150)
image_load#(img#, "https://picsum.photos/200/150")

aff# = affine#(img#)
affine_rotation#(aff#, 10)
affine_scale#(aff#, 1.0)

' Scale slider (0.5 to 2.0)
lblScale# = label#(frm#, "Scale: 1.00", 50, 200)
trkScale# = trackbar#(frm#)
trackbar_bounds#(trkScale#, 50, 230, 350, 30)
trackbar_max#(trkScale#, 150)
trackbar_value#(trkScale#, 50)
trackbar_onchange#(trkScale#, "OnScaleChange")

form_show(frm#)

function OnScaleChange(sender#) local s
  let s = 0.5 + (trackbar_value(trkScale#) / 100)
  affine_scale#(aff#, s)
  label_text#(lblScale#, "Scale: " + stri$(s, 2))
endfunction

Best Practices

PracticeWhy
Use affine_enabled# to toggle instead of affine_freeAvoids destroying and recreating the effect; better performance for on/off scenarios
Keep center at (0.5, 0.5) for symmetric transformsRotation and scaling around the visual center looks most natural
Combine with FloatAnimationLib for animated rotationAnimate the rotation property for smooth spinning effects
Use scale values between 0.1 and 5.0Extreme values may cause rendering artifacts or performance issues
Adjust center before rotation for pivot effectsSetting center to (0, 0) makes the control rotate around its top-left corner
Check affine_error() after creationCatches nil or invalid parent controls early
One effect per control is typicalMultiple affine effects stack but may produce unexpected results; use one and combine rotation + scale
Scale down slightly when rotating to avoid clippingRotated corners may extend beyond the original bounding box

Quick Reference

FunctionSignatureDescription
ERROR HANDLING
affine_error()affine_error@Last error code
affine_errormsg$()affine_errormsg$@Last error message
affine_strerror$(code)affine_strerror$@nError code to text
affine_clearerror()affine_clearerror@Clear error state
CREATION & DESTRUCTION
affine#(parent#)affine#@#Create effect on control
affine_free(effect#)affine_free@#Destroy effect
TRANSFORM PROPERTIES
affine_centerx#(effect#, val)affine_centerx#@#nSet center X (0.0–1.0)
affine_centerx(effect#)affine_centerx@#Get center X
affine_centery#(effect#, val)affine_centery#@#nSet center Y (0.0–1.0)
affine_centery(effect#)affine_centery@#Get center Y
affine_rotation#(effect#, deg)affine_rotation#@#nSet rotation (degrees)
affine_rotation(effect#)affine_rotation@#Get rotation
affine_scale#(effect#, val)affine_scale#@#nSet uniform scale
affine_scale(effect#)affine_scale@#Get scale
EFFECT CONTROL
affine_enabled#(effect#, val)affine_enabled#@#nEnable (1) / disable (0)
affine_enabled(effect#)affine_enabled@#Get enabled state
affine_trigger#(effect#, str$)affine_trigger#@#$Set trigger string
affine_trigger$(effect#)affine_trigger$@#Get trigger string

18 functions. Part of the Plan9Basic visual effects library system.

See Also

  • PerspectiveTransformEffectLib — 3D perspective transforms with depth
  • MagnifyEffectLib — Magnifying glass effect for zoom regions
  • SwirlEffectLib — Swirl distortion around a center point
  • FloatAnimationLib — Animate numeric properties (combine with rotation/scale for animated transforms)