source: trunk/Packages/Graphics32/GR32_Transforms.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 53.5 KB
Line 
1unit GR32_Transforms;
2
3(* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1 or LGPL 2.1 with linking exception
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Alternatively, the contents of this file may be used under the terms of the
17 * Free Pascal modified version of the GNU Lesser General Public License
18 * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
19 * of this license are applicable instead of those above.
20 * Please see the file LICENSE.txt for additional information concerning this
21 * license.
22 *
23 * The Original Code is Graphics32
24 *
25 * The Initial Developer of the Original Code is
26 * Alex A. Denisov
27 *
28 * Portions created by the Initial Developer are Copyright (C) 2000-2009
29 * the Initial Developer. All Rights Reserved.
30 *
31 * Contributor(s):
32 * Andre Beckedorf <Andre@metaException.de>
33 * Mattias Andersson <Mattias@Centaurix.com>
34 * J. Tulach <tulach@position.cz>
35 * Michael Hansen <dyster_tid@hotmail.com>
36 * Peter Larson
37 *
38 * ***** END LICENSE BLOCK ***** *)
39
40interface
41
42{$I GR32.inc}
43
44uses
45{$IFDEF FPC}
46 LCLIntf,
47{$ELSE}
48 Windows,
49{$ENDIF}
50 SysUtils, Classes, Types, GR32, GR32_VectorMaps, GR32_Rasterizers;
51
52type
53 ETransformError = class(Exception);
54 ETransformNotImplemented = class(Exception);
55
56type
57 TFloatMatrix = array [0..2, 0..2] of TFloat; // 3x3 TFloat precision
58 TFixedMatrix = array [0..2, 0..2] of TFixed; // 3x3 fixed precision
59
60const
61 IdentityMatrix: TFloatMatrix = (
62 (1, 0, 0),
63 (0, 1, 0),
64 (0, 0, 1));
65
66type
67 TVector3f = array [0..2] of TFloat;
68 TVector3i = array [0..2] of Integer;
69
70// Matrix conversion routines
71function FixedMatrix(const FloatMatrix: TFloatMatrix): TFixedMatrix; overload;
72function FloatMatrix(const FixedMatrix: TFixedMatrix): TFloatMatrix; overload;
73
74procedure Adjoint(var M: TFloatMatrix);
75function Determinant(const M: TFloatMatrix): TFloat;
76procedure Scale(var M: TFloatMatrix; Factor: TFloat);
77procedure Invert(var M: TFloatMatrix);
78function Mult(const M1, M2: TFloatMatrix): TFloatMatrix;
79function VectorTransform(const M: TFloatMatrix; const V: TVector3f): TVector3f;
80
81type
82 TTransformation = class(TNotifiablePersistent)
83 private
84 FSrcRect: TFloatRect;
85 procedure SetSrcRect(const Value: TFloatRect);
86 protected
87 TransformValid: Boolean;
88 procedure PrepareTransform; virtual;
89 procedure ReverseTransformInt(DstX, DstY: Integer; out SrcX, SrcY: Integer); virtual;
90 procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); virtual;
91 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); virtual;
92 procedure TransformInt(SrcX, SrcY: Integer; out DstX, DstY: Integer); virtual;
93 procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); virtual;
94 procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); virtual;
95 public
96 constructor Create; virtual;
97 procedure Changed; override;
98 function HasTransformedBounds: Boolean; virtual;
99 function GetTransformedBounds: TFloatRect; overload;
100 function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; overload; virtual;
101 function ReverseTransform(const P: TPoint): TPoint; overload; virtual;
102 function ReverseTransform(const P: TFixedPoint): TFixedPoint; overload; virtual;
103 function ReverseTransform(const P: TFloatPoint): TFloatPoint; overload; virtual;
104 function Transform(const P: TPoint): TPoint; overload; virtual;
105 function Transform(const P: TFixedPoint): TFixedPoint; overload; virtual;
106 function Transform(const P: TFloatPoint): TFloatPoint; overload; virtual;
107 property SrcRect: TFloatRect read FSrcRect write SetSrcRect;
108 end;
109 TTransformationClass = class of TTransformation;
110
111 TNestedTransformation = class(TTransformation)
112 private
113 FItems: TList;
114 FOwner: TPersistent;
115 function GetCount: Integer;
116 function GetItem(Index: Integer): TTransformation;
117 procedure SetItem(Index: Integer; const Value: TTransformation);
118 protected
119 procedure PrepareTransform; override;
120 procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
121 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
122 procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
123 procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
124 public
125 constructor Create; override;
126 destructor Destroy; override;
127 function Add(ItemClass: TTransformationClass): TTransformation;
128 procedure Clear;
129 procedure Delete(Index: Integer);
130 function Insert(Index: Integer; ItemClass: TTransformationClass): TTransformation;
131
132 property Owner: TPersistent read FOwner;
133 property Count: Integer read GetCount;
134 property Items[Index: Integer]: TTransformation read GetItem write SetItem; default;
135 end;
136
137 T3x3Transformation = class(TTransformation)
138 protected
139 FMatrix, FInverseMatrix: TFloatMatrix;
140 FFixedMatrix, FInverseFixedMatrix: TFixedMatrix;
141 procedure PrepareTransform; override;
142 procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
143 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
144 procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
145 procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
146 public
147 property Matrix: TFloatMatrix read FMatrix;
148 end;
149
150 TAffineTransformation = class(T3x3Transformation)
151 private
152 FStack: ^TFloatMatrix;
153 FStackLevel: Integer;
154 public
155 constructor Create; override;
156
157 function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
158 procedure Push;
159 procedure Pop;
160 procedure Clear; overload;
161 procedure Clear(BaseMatrix: TFloatMatrix); overload;
162 procedure Rotate(Alpha: TFloat); overload; // degrees
163 procedure Rotate(Cx, Cy, Alpha: TFloat); overload; // degrees
164 procedure Skew(Fx, Fy: TFloat);
165 procedure Scale(Sx, Sy: TFloat); overload;
166 procedure Scale(Value: TFloat); overload;
167 procedure Translate(Dx, Dy: TFloat);
168 end;
169
170 TProjectiveTransformation = class(T3x3Transformation)
171 private
172 FQuadX: array [0..3] of TFloat;
173 FQuadY: array [0..3] of TFloat;
174 procedure SetX(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
175 procedure SetY(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
176 function GetX(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
177 function GetY(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
178 protected
179 procedure PrepareTransform; override;
180 procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
181 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
182 procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
183 procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
184 public
185 function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
186 property X[Index: Integer]: TFloat read GetX write SetX;
187 property Y[index: Integer]: TFloat read GetX write SetY;
188 published
189 property X0: TFloat index 0 read GetX write SetX;
190 property X1: TFloat index 1 read GetX write SetX;
191 property X2: TFloat index 2 read GetX write SetX;
192 property X3: TFloat index 3 read GetX write SetX;
193 property Y0: TFloat index 0 read GetY write SetY;
194 property Y1: TFloat index 1 read GetY write SetY;
195 property Y2: TFloat index 2 read GetY write SetY;
196 property Y3: TFloat index 3 read GetY write SetY;
197 end;
198
199 TTwirlTransformation = class(TTransformation)
200 private
201 Frx, Fry: TFloat;
202 FTwirl: TFloat;
203 procedure SetTwirl(const Value: TFloat);
204 protected
205 procedure PrepareTransform; override;
206 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
207 public
208 constructor Create; override;
209 function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
210 published
211 property Twirl: TFloat read FTwirl write SetTwirl;
212 end;
213
214 TBloatTransformation = class(TTransformation)
215 private
216 FBloatPower: TFloat;
217 FBP: TFloat;
218 FPiW, FPiH: TFloat;
219 procedure SetBloatPower(const Value: TFloat);
220 protected
221 procedure PrepareTransform; override;
222 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
223 procedure TransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
224 public
225 constructor Create; override;
226 published
227 property BloatPower: TFloat read FBloatPower write SetBloatPower;
228 end;
229
230 TDisturbanceTransformation = class(TTransformation)
231 private
232 FDisturbance: TFloat;
233 procedure SetDisturbance(const Value: TFloat);
234 protected
235 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
236 public
237 function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
238 published
239 property Disturbance: TFloat read FDisturbance write SetDisturbance;
240 end;
241
242 TFishEyeTransformation = class(TTransformation)
243 private
244 Frx, Fry: TFloat;
245 Faw, Fsr: TFloat;
246 Sx, Sy: TFloat;
247 FMinR: TFloat;
248 protected
249 procedure PrepareTransform; override;
250 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
251 end;
252
253 TPolarTransformation = class(TTransformation)
254 private
255 FDstRect: TFloatRect;
256 FPhase: TFloat;
257 Sx, Sy, Cx, Cy, Dx, Dy, Rt, Rt2, Rr, Rcx, Rcy: TFloat;
258 procedure SetDstRect(const Value: TFloatRect);
259 procedure SetPhase(const Value: TFloat);
260 protected
261 procedure PrepareTransform; override;
262 procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
263 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
264 public
265 property DstRect: TFloatRect read FDstRect write SetDstRect;
266 property Phase: TFloat read FPhase write SetPhase;
267 end;
268
269 TPathTransformation = class(TTransformation)
270 private
271 FTopLength: TFloat;
272 FBottomLength: TFloat;
273 FBottomCurve: TArrayOfFloatPoint;
274 FTopCurve: TArrayOfFloatPoint;
275 FTopHypot, FBottomHypot: array of record Dist, RecDist: TFloat end;
276 procedure SetBottomCurve(const Value: TArrayOfFloatPoint);
277 procedure SetTopCurve(const Value: TArrayOfFloatPoint);
278 protected
279 rdx, rdy: TFloat;
280 procedure PrepareTransform; override;
281 procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
282 public
283 destructor Destroy; override;
284 property TopCurve: TArrayOfFloatPoint read FTopCurve write SetTopCurve;
285 property BottomCurve: TArrayOfFloatPoint read FBottomCurve write SetBottomCurve;
286 end;
287
288 TRemapTransformation = class(TTransformation)
289 private
290 FVectorMap : TVectorMap;
291 FScalingFixed: TFixedVector;
292 FScalingFloat: TFloatVector;
293 FCombinedScalingFixed: TFixedVector;
294 FCombinedScalingFloat: TFloatVector;
295 FSrcTranslationFixed: TFixedVector;
296 FSrcScaleFixed: TFixedVector;
297 FDstTranslationFixed: TFixedVector;
298 FDstScaleFixed: TFixedVector;
299 FSrcTranslationFloat: TFloatVector;
300 FSrcScaleFloat: TFloatVector;
301 FDstTranslationFloat: TFloatVector;
302 FDstScaleFloat: TFloatVector;
303 FOffsetFixed : TFixedVector;
304 FOffsetInt : TPoint;
305 FMappingRect: TFloatRect;
306 FOffset: TFloatVector;
307 procedure SetMappingRect(Rect: TFloatRect);
308 procedure SetOffset(const Value: TFloatVector);
309 protected
310 procedure PrepareTransform; override;
311 procedure ReverseTransformInt(DstX, DstY: Integer; out SrcX, SrcY: Integer); override;
312 procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
313 procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
314 public
315 constructor Create; override;
316 destructor Destroy; override;
317 function HasTransformedBounds: Boolean; override;
318 function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
319 procedure Scale(Sx, Sy: TFloat);
320 property MappingRect: TFloatRect read FMappingRect write SetMappingRect;
321 property Offset: TFloatVector read FOffset write SetOffset;
322 property VectorMap: TVectorMap read FVectorMap write FVectorMap;
323 end;
324
325function TransformPoints(Points: TArrayOfArrayOfFixedPoint; Transformation: TTransformation): TArrayOfArrayOfFixedPoint;
326
327procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation); overload;
328procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
329 const DstClip: TRect); overload;
330procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
331 Rasterizer: TRasterizer); overload;
332procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
333 Rasterizer: TRasterizer; const DstClip: TRect); overload;
334
335procedure RasterizeTransformation(Vectormap: TVectormap;
336 Transformation: TTransformation; DstRect: TRect;
337 CombineMode: TVectorCombineMode = vcmAdd;
338 CombineCallback: TVectorCombineEvent = nil);
339
340procedure SetBorderTransparent(ABitmap: TCustomBitmap32; ARect: TRect);
341
342{ FullEdge controls how the bitmap is resampled }
343var
344 FullEdge: Boolean = True;
345
346resourcestring
347 RCStrReverseTransformationNotImplemented = 'Reverse transformation is not implemented in %s.';
348 RCStrForwardTransformationNotImplemented = 'Forward transformation is not implemented in %s.';
349 RCStrTopBottomCurveNil = 'Top or bottom curve is nil';
350
351implementation
352
353uses
354 Math, GR32_Blend, GR32_LowLevel, GR32_Math, GR32_Bindings,
355 GR32_Resamplers;
356
357resourcestring
358 RCStrSrcRectIsEmpty = 'SrcRect is empty!';
359 RCStrMappingRectIsEmpty = 'MappingRect is empty!';
360 RStrStackEmpty = 'Stack empty';
361
362type
363 {provides access to proctected members of TCustomBitmap32 by typecasting}
364 TTransformationAccess = class(TTransformation);
365
366var
367 DET32: function(a1, a2, b1, b2: Single): Single;
368 DET64: function(a1, a2, b1, b2: Double): Double;
369
370
371{ A bit of linear algebra }
372
373function DET32_Pas(a1, a2, b1, b2: Single): Single; overload;
374begin
375 Result := a1 * b2 - a2 * b1;
376end;
377
378function DET64_Pas(a1, a2, b1, b2: Double): Double; overload;
379begin
380 Result := a1 * b2 - a2 * b1;
381end;
382
383{$IFNDEF PUREPASCAL}
384function DET32_ASM(a1, a2, b1, b2: Single): Single; overload;
385asm
386{$IFDEF CPU64}
387 MULSS XMM0, XMM3
388 MULSS XMM1, XMM2
389 ADDSS XMM0, XMM1
390{$ELSE}
391 FLD A1.Single
392 FMUL B2.Single
393 FLD A2.Single
394 FMUL B1.Single
395 FSUBP
396{$ENDIF}
397end;
398
399function DET64_ASM(a1, a2, b1, b2: Double): Double; overload;
400asm
401{$IFDEF CPU64}
402 MULSD XMM0, XMM3
403 MULSD XMM1, XMM2
404 ADDSD XMM0, XMM1
405{$ELSE}
406 FLD A1.Double
407 FMUL B2.Double
408 FLD A2.Double
409 FMUL B1.Double
410 FSUBP
411{$ENDIF}
412end;
413{$ENDIF}
414
415{ implementation of detereminant for TFloat precision }
416
417function _DET(a1, a2, b1, b2: TFloat): TFloat; overload; {$IFDEF UseInlining} inline; {$ENDIF}
418begin
419 Result := a1 * b2 - a2 * b1;
420end;
421
422function _DET(a1, a2, a3, b1, b2, b3, c1, c2, c3: TFloat): TFloat; overload; {$IFDEF UseInlining} inline; {$ENDIF}
423begin
424 Result :=
425 a1 * (b2 * c3 - b3 * c2) -
426 b1 * (a2 * c3 - a3 * c2) +
427 c1 * (a2 * b3 - a3 * b2);
428end;
429
430procedure Adjoint(var M: TFloatMatrix);
431var
432 Tmp: TFloatMatrix;
433begin
434 Tmp := M;
435
436 M[0,0] := _DET(Tmp[1,1], Tmp[1,2], Tmp[2,1], Tmp[2,2]);
437 M[0,1] := -_DET(Tmp[0,1], Tmp[0,2], Tmp[2,1], Tmp[2,2]);
438 M[0,2] := _DET(Tmp[0,1], Tmp[0,2], Tmp[1,1], Tmp[1,2]);
439
440 M[1,0] := -_DET(Tmp[1,0], Tmp[1,2], Tmp[2,0], Tmp[2,2]);
441 M[1,1] := _DET(Tmp[0,0], Tmp[0,2], Tmp[2,0], Tmp[2,2]);
442 M[1,2] := -_DET(Tmp[0,0], Tmp[0,2], Tmp[1,0], Tmp[1,2]);
443
444 M[2,0] := _DET(Tmp[1,0], Tmp[1,1], Tmp[2,0], Tmp[2,1]);
445 M[2,1] := -_DET(Tmp[0,0], Tmp[0,1], Tmp[2,0], Tmp[2,1]);
446 M[2,2] := _DET(Tmp[0,0], Tmp[0,1], Tmp[1,0], Tmp[1,1]);
447end;
448
449function Determinant(const M: TFloatMatrix): TFloat;
450begin
451 Result := _DET(M[0,0], M[1,0], M[2,0],
452 M[0,1], M[1,1], M[2,1],
453 M[0,2], M[1,2], M[2,2]);
454end;
455
456procedure Scale(var M: TFloatMatrix; Factor: TFloat);
457var
458 i, j: Integer;
459begin
460 for i := 0 to 2 do
461 for j := 0 to 2 do
462 M[i,j] := M[i,j] * Factor;
463end;
464
465procedure Invert(var M: TFloatMatrix);
466var
467 Det: TFloat;
468begin
469 Det := Determinant(M);
470 if Abs(Det) < 1E-5 then M := IdentityMatrix
471 else
472 begin
473 Adjoint(M);
474 Scale(M, 1 / Det);
475 end;
476end;
477
478function Mult(const M1, M2: TFloatMatrix): TFloatMatrix;
479var
480 i, j: Integer;
481begin
482 for i := 0 to 2 do
483 for j := 0 to 2 do
484 Result[i, j] :=
485 M1[0, j] * M2[i, 0] +
486 M1[1, j] * M2[i, 1] +
487 M1[2, j] * M2[i, 2];
488end;
489
490function VectorTransform(const M: TFloatMatrix; const V: TVector3f): TVector3f;
491begin
492 Result[0] := M[0,0] * V[0] + M[1,0] * V[1] + M[2,0] * V[2];
493 Result[1] := M[0,1] * V[0] + M[1,1] * V[1] + M[2,1] * V[2];
494 Result[2] := M[0,2] * V[0] + M[1,2] * V[1] + M[2,2] * V[2];
495end;
496
497{ Transformation functions }
498
499function TransformPoints(Points: TArrayOfArrayOfFixedPoint; Transformation: TTransformation): TArrayOfArrayOfFixedPoint;
500var
501 I, J: Integer;
502begin
503 if Points = nil then
504 Result := nil
505 else
506 begin
507 SetLength(Result, Length(Points));
508 Transformation.PrepareTransform;
509
510 for I := 0 to High(Result) do
511 begin
512 SetLength(Result[I], Length(Points[I]));
513 if Length(Result[I]) > 0 then
514 for J := 0 to High(Result[I]) do
515 Transformation.TransformFixed(Points[I][J].X, Points[I][J].Y, Result[I][J].X, Result[I][J].Y);
516 end;
517 end;
518end;
519
520procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation);
521var
522 Rasterizer: TRasterizer;
523begin
524 Rasterizer := DefaultRasterizerClass.Create;
525 try
526 Transform(Dst, Src, Transformation, Rasterizer);
527 finally
528 Rasterizer.Free;
529 end;
530end;
531
532procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; const DstClip: TRect);
533var
534 Rasterizer: TRasterizer;
535begin
536 Rasterizer := DefaultRasterizerClass.Create;
537 try
538 Transform(Dst, Src, Transformation, Rasterizer, DstClip);
539 finally
540 Rasterizer.Free;
541 end;
542end;
543
544procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
545 Rasterizer: TRasterizer);
546begin
547 Transform(Dst, Src, Transformation, Rasterizer, Dst.BoundsRect);
548end;
549
550procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
551 Rasterizer: TRasterizer; const DstClip: TRect);
552var
553 DstRect: TRect;
554 Transformer: TTransformer;
555begin
556 GR32.IntersectRect(DstRect, DstClip, Dst.ClipRect);
557
558 if (DstRect.Right < DstRect.Left) or (DstRect.Bottom < DstRect.Top) then Exit;
559
560 if not Dst.MeasuringMode then
561 begin
562 Transformer := TTransformer.Create(Src.Resampler, Transformation);
563 try
564 Rasterizer.Sampler := Transformer;
565 Rasterizer.Rasterize(Dst, DstRect, Src);
566 finally
567 EMMS;
568 Transformer.Free;
569 end;
570 end;
571 Dst.Changed(DstRect);
572end;
573
574procedure SetBorderTransparent(ABitmap: TCustomBitmap32; ARect: TRect);
575var
576 I: Integer;
577begin
578 GR32.IntersectRect(ARect, ARect, ABitmap.BoundsRect);
579 with ARect, ABitmap do
580 if (Right > Left) and (Bottom > Top) and
581 (Left < ClipRect.Right) and (Top < ClipRect.Bottom) and
582 (Right > ClipRect.Left) and (Bottom > ClipRect.Top) then
583 begin
584 Dec(Right);
585 Dec(Bottom);
586 for I := Left to Right do
587 begin
588 ABitmap[I, Top] := ABitmap[I, Top] and $00FFFFFF;
589 ABitmap[I, Bottom] := ABitmap[I, Bottom] and $00FFFFFF;
590 end;
591 for I := Top to Bottom do
592 begin
593 ABitmap[Left, I] := ABitmap[Left, I] and $00FFFFFF;
594 ABitmap[Right, I] := ABitmap[Right, I] and $00FFFFFF;
595 end;
596 Changed;
597 end;
598end;
599
600{ TTransformation }
601
602function TTransformation.GetTransformedBounds: TFloatRect;
603begin
604 Result := GetTransformedBounds(FSrcRect);
605end;
606
607procedure TTransformation.Changed;
608begin
609 TransformValid := False;
610 inherited;
611end;
612
613constructor TTransformation.Create;
614begin
615 // virtual constructor to be overriden in derived classes
616end;
617
618function TTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
619begin
620 Result := ASrcRect;
621end;
622
623function TTransformation.HasTransformedBounds: Boolean;
624begin
625 Result := True;
626end;
627
628procedure TTransformation.PrepareTransform;
629begin
630 // Dummy
631end;
632
633function TTransformation.ReverseTransform(const P: TFloatPoint): TFloatPoint;
634begin
635 if not TransformValid then PrepareTransform;
636 ReverseTransformFloat(P.X, P.Y, Result.X, Result.Y);
637end;
638
639function TTransformation.ReverseTransform(const P: TFixedPoint): TFixedPoint;
640begin
641 if not TransformValid then PrepareTransform;
642 ReverseTransformFixed(P.X, P.Y, Result.X, Result.Y);
643end;
644
645function TTransformation.ReverseTransform(const P: TPoint): TPoint;
646begin
647 if not TransformValid then PrepareTransform;
648 ReverseTransformInt(P.X, P.Y, Result.X, Result.Y);
649end;
650
651procedure TTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
652 out SrcX, SrcY: TFixed);
653var
654 X, Y: TFloat;
655begin
656 ReverseTransformFloat(DstX * FixedToFloat, DstY * FixedToFloat, X, Y);
657 SrcX := Fixed(X);
658 SrcY := Fixed(Y);
659end;
660
661procedure TTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
662 out SrcX, SrcY: TFloat);
663begin
664 // ReverseTransformFloat is the top precisionlevel, all descendants must override at least this level!
665 raise ETransformNotImplemented.CreateFmt(RCStrReverseTransformationNotImplemented, [Self.Classname]);
666end;
667
668procedure TTransformation.ReverseTransformInt(DstX, DstY: Integer;
669 out SrcX, SrcY: Integer);
670var
671 X, Y: TFixed;
672begin
673 ReverseTransformFixed(DstX shl 16, DstY shl 16, X, Y);
674 SrcX := FixedRound(X);
675 SrcY := FixedRound(Y);
676end;
677
678procedure TTransformation.SetSrcRect(const Value: TFloatRect);
679begin
680 FSrcRect := Value;
681 Changed;
682end;
683
684function TTransformation.Transform(const P: TFloatPoint): TFloatPoint;
685begin
686 if not TransformValid then PrepareTransform;
687 TransformFloat(P.X, P.Y, Result.X, Result.Y);
688end;
689
690function TTransformation.Transform(const P: TFixedPoint): TFixedPoint;
691begin
692 if not TransformValid then PrepareTransform;
693 TransformFixed(P.X, P.Y, Result.X, Result.Y);
694end;
695
696function TTransformation.Transform(const P: TPoint): TPoint;
697begin
698 if not TransformValid then PrepareTransform;
699 TransformInt(P.X, P.Y, Result.X, Result.Y);
700end;
701
702procedure TTransformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
703 DstY: TFixed);
704var
705 X, Y: TFloat;
706begin
707 TransformFloat(SrcX * FixedToFloat, SrcY * FixedToFloat, X, Y);
708 DstX := Fixed(X);
709 DstY := Fixed(Y);
710end;
711
712procedure TTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat);
713begin
714 // TransformFloat is the top precisionlevel, all descendants must override at least this level!
715 raise ETransformNotImplemented.CreateFmt(RCStrForwardTransformationNotImplemented, [Self.Classname]);
716end;
717
718procedure TTransformation.TransformInt(SrcX, SrcY: Integer; out DstX, DstY: Integer);
719var
720 X, Y: TFixed;
721begin
722 TransformFixed(SrcX shl 16, SrcY shl 16, X, Y);
723 DstX := FixedRound(X);
724 DstY := FixedRound(Y);
725end;
726
727
728{ TNestedTransformation }
729
730constructor TNestedTransformation.Create;
731begin
732 FItems := TList.Create;
733end;
734
735destructor TNestedTransformation.Destroy;
736begin
737 if Assigned(FItems) then Clear;
738 FItems.Free;
739 inherited;
740end;
741
742function TNestedTransformation.Add(
743 ItemClass: TTransformationClass): TTransformation;
744begin
745 Result := ItemClass.Create;
746 {$IFDEF NEXTGEN}
747 Result.__ObjAddRef;
748 {$ENDIF}
749 FItems.Add(Result);
750end;
751
752procedure TNestedTransformation.Clear;
753begin
754 BeginUpdate;
755 try
756 while FItems.Count > 0 do
757 Delete(FItems.Count - 1);
758 finally
759 EndUpdate;
760 end;
761end;
762
763procedure TNestedTransformation.Delete(Index: Integer);
764begin
765 TTransformation(FItems[Index]).Free;
766 FItems.Delete(Index);
767end;
768
769function TNestedTransformation.GetCount: Integer;
770begin
771 Result := FItems.Count;
772end;
773
774function TNestedTransformation.GetItem(Index: Integer): TTransformation;
775begin
776 Result := FItems[Index];
777end;
778
779function TNestedTransformation.Insert(Index: Integer;
780 ItemClass: TTransformationClass): TTransformation;
781begin
782 BeginUpdate;
783 try
784 Result := Add(ItemClass);
785 finally
786 EndUpdate;
787 end;
788end;
789
790procedure TNestedTransformation.PrepareTransform;
791var
792 Index: Integer;
793begin
794 for Index := 0 to Count - 1 do
795 TTransformation(FItems[Index]).PrepareTransform;
796end;
797
798procedure TNestedTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
799 out SrcX, SrcY: TFixed);
800var
801 Index: Integer;
802begin
803 for Index := 0 to Count - 1 do
804 begin
805 TTransformation(FItems[Index]).ReverseTransformFixed(DstX, DstY, SrcX,
806 SrcY);
807 DstX := SrcX;
808 DstY := SrcY;
809 end;
810end;
811
812procedure TNestedTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
813 out SrcX, SrcY: TFloat);
814var
815 Index: Integer;
816begin
817 for Index := 0 to Count - 1 do
818 begin
819 TTransformation(FItems[Index]).ReverseTransformFloat(DstX, DstY, SrcX,
820 SrcY);
821 DstX := SrcX;
822 DstY := SrcY;
823 end;
824end;
825
826procedure TNestedTransformation.SetItem(Index: Integer;
827 const Value: TTransformation);
828begin
829 TCollectionItem(FItems[Index]).Assign(Value);
830end;
831
832procedure TNestedTransformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
833 DstY: TFixed);
834var
835 Index: Integer;
836begin
837 for Index := 0 to Count - 1 do
838 begin
839 TTransformation(FItems[Index]).TransformFixed(SrcX, SrcY, DstX, DstY);
840 SrcX := DstX;
841 SrcY := DstY;
842 end;
843end;
844
845procedure TNestedTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
846 DstY: TFloat);
847var
848 Index: Integer;
849begin
850 for Index := 0 to Count - 1 do
851 begin
852 TTransformation(FItems[Index]).TransformFloat(SrcX, SrcY, DstX, DstY);
853 SrcX := DstX;
854 SrcY := DstY;
855 end;
856end;
857
858
859{ T3x3Transformation }
860
861procedure T3x3Transformation.PrepareTransform;
862begin
863 FInverseMatrix := Matrix;
864 Invert(FInverseMatrix);
865
866 // calculate a fixed point (65536) factors
867 FInverseFixedMatrix := FixedMatrix(FInverseMatrix);
868 FFixedMatrix := FixedMatrix(Matrix);
869
870 TransformValid := True;
871end;
872
873procedure T3x3Transformation.ReverseTransformFixed(DstX, DstY: TFixed; out SrcX,
874 SrcY: TFixed);
875begin
876 SrcX := FixedMul(DstX, FInverseFixedMatrix[0, 0]) +
877 FixedMul(DstY, FInverseFixedMatrix[1, 0]) + FInverseFixedMatrix[2, 0];
878 SrcY := FixedMul(DstX, FInverseFixedMatrix[0, 1]) +
879 FixedMul(DstY, FInverseFixedMatrix[1, 1]) + FInverseFixedMatrix[2, 1];
880end;
881
882procedure T3x3Transformation.ReverseTransformFloat(DstX, DstY: TFloat; out SrcX,
883 SrcY: TFloat);
884begin
885 SrcX := DstX * FInverseMatrix[0, 0] + DstY * FInverseMatrix[1, 0] +
886 FInverseMatrix[2, 0];
887 SrcY := DstX * FInverseMatrix[0, 1] + DstY * FInverseMatrix[1, 1] +
888 FInverseMatrix[2, 1];
889end;
890
891procedure T3x3Transformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
892 DstY: TFixed);
893begin
894 DstX := FixedMul(SrcX, FFixedMatrix[0, 0]) +
895 FixedMul(SrcY, FFixedMatrix[1, 0]) + FFixedMatrix[2, 0];
896 DstY := FixedMul(SrcX, FFixedMatrix[0, 1]) +
897 FixedMul(SrcY, FFixedMatrix[1, 1]) + FFixedMatrix[2, 1];
898end;
899
900procedure T3x3Transformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
901 DstY: TFloat);
902begin
903 DstX := SrcX * Matrix[0, 0] + SrcY * Matrix[1, 0] + Matrix[2, 0];
904 DstY := SrcX * Matrix[0, 1] + SrcY * Matrix[1, 1] + Matrix[2, 1];
905end;
906
907
908{ TAffineTransformation }
909
910constructor TAffineTransformation.Create;
911begin
912 FStackLevel := 0;
913 FStack := nil;
914 Clear;
915end;
916
917procedure TAffineTransformation.Clear;
918begin
919 FMatrix := IdentityMatrix;
920 Changed;
921end;
922
923procedure TAffineTransformation.Clear(BaseMatrix: TFloatMatrix);
924begin
925 FMatrix := BaseMatrix;
926 Changed;
927end;
928
929function TAffineTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
930var
931 V1, V2, V3, V4: TVector3f;
932begin
933 V1[0] := ASrcRect.Left; V1[1] := ASrcRect.Top; V1[2] := 1;
934 V2[0] := ASrcRect.Right; V2[1] := V1[1]; V2[2] := 1;
935 V3[0] := V1[0]; V3[1] := ASrcRect.Bottom; V3[2] := 1;
936 V4[0] := V2[0]; V4[1] := V3[1]; V4[2] := 1;
937 V1 := VectorTransform(Matrix, V1);
938 V2 := VectorTransform(Matrix, V2);
939 V3 := VectorTransform(Matrix, V3);
940 V4 := VectorTransform(Matrix, V4);
941 Result.Left := Min(Min(V1[0], V2[0]), Min(V3[0], V4[0]));
942 Result.Right := Max(Max(V1[0], V2[0]), Max(V3[0], V4[0]));
943 Result.Top := Min(Min(V1[1], V2[1]), Min(V3[1], V4[1]));
944 Result.Bottom := Max(Max(V1[1], V2[1]), Max(V3[1], V4[1]));
945end;
946
947procedure TAffineTransformation.Push;
948begin
949 Inc(FStackLevel);
950 ReallocMem(FStack, FStackLevel * SizeOf(TFloatMatrix));
951 Move(FMatrix, FStack^[FStackLevel - 1], SizeOf(TFloatMatrix));
952end;
953
954procedure TAffineTransformation.Pop;
955begin
956 if FStackLevel <= 0 then
957 raise Exception.Create(RStrStackEmpty);
958
959 Move(FStack^[FStackLevel - 1], FMatrix, SizeOf(TFloatMatrix));
960 Dec(FStackLevel);
961 Changed;
962end;
963
964procedure TAffineTransformation.Rotate(Alpha: TFloat);
965var
966 S, C: TFloat;
967 M: TFloatMatrix;
968begin
969 Alpha := DegToRad(Alpha);
970 GR32_Math.SinCos(Alpha, S, C);
971 M := IdentityMatrix;
972 M[0, 0] := C; M[1, 0] := S;
973 M[0, 1] := -S; M[1, 1] := C;
974 FMatrix := Mult(M, Matrix);
975 Changed;
976end;
977
978procedure TAffineTransformation.Rotate(Cx, Cy, Alpha: TFloat);
979var
980 S, C: TFloat;
981 M: TFloatMatrix;
982begin
983 if (Cx <> 0) or (Cy <> 0) then Translate(-Cx, -Cy);
984 Alpha := DegToRad(Alpha);
985 GR32_Math.SinCos(Alpha, S, C);
986 M := IdentityMatrix;
987 M[0, 0] := C; M[1, 0] := S;
988 M[0, 1] := -S; M[1, 1] := C;
989 FMatrix := Mult(M, Matrix);
990 if (Cx <> 0) or (Cy <> 0) then Translate(Cx, Cy);
991 Changed;
992end;
993
994procedure TAffineTransformation.Scale(Sx, Sy: TFloat);
995var
996 M: TFloatMatrix;
997begin
998 M := IdentityMatrix;
999 M[0, 0] := Sx;
1000 M[1, 1] := Sy;
1001 FMatrix := Mult(M, Matrix);
1002 Changed;
1003end;
1004
1005procedure TAffineTransformation.Scale(Value: TFloat);
1006var
1007 M: TFloatMatrix;
1008begin
1009 M := IdentityMatrix;
1010 M[0, 0] := Value;
1011 M[1, 1] := Value;
1012 FMatrix := Mult(M, Matrix);
1013 Changed;
1014end;
1015
1016procedure TAffineTransformation.Skew(Fx, Fy: TFloat);
1017var
1018 M: TFloatMatrix;
1019begin
1020 M := IdentityMatrix;
1021 M[1, 0] := Fx;
1022 M[0, 1] := Fy;
1023 FMatrix := Mult(M, Matrix);
1024 Changed;
1025end;
1026
1027procedure TAffineTransformation.Translate(Dx, Dy: TFloat);
1028var
1029 M: TFloatMatrix;
1030begin
1031 M := IdentityMatrix;
1032 M[2, 0] := Dx;
1033 M[2, 1] := Dy;
1034 FMatrix := Mult(M, Matrix);
1035
1036 Changed;
1037end;
1038
1039
1040{ TProjectiveTransformation }
1041
1042function TProjectiveTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
1043begin
1044 Result.Left := Min(Min(FQuadX[0], FQuadX[1]), Min(FQuadX[2], FQuadX[3]));
1045 Result.Right := Max(Max(FQuadX[0], FQuadX[1]), Max(FQuadX[2], FQuadX[3]));
1046 Result.Top := Min(Min(FQuadY[0], FQuadY[1]), Min(FQuadY[2], FQuadY[3]));
1047 Result.Bottom := Max(Max(FQuadY[0], FQuadY[1]), Max(FQuadY[2], FQuadY[3]));
1048end;
1049
1050function TProjectiveTransformation.GetX(Index: Integer): TFloat;
1051begin
1052 Result := FQuadX[Index];
1053end;
1054
1055function TProjectiveTransformation.GetY(Index: Integer): TFloat;
1056begin
1057 Result := FQuadY[Index];
1058end;
1059
1060procedure TProjectiveTransformation.PrepareTransform;
1061var
1062 dx1, dx2, px, dy1, dy2, py: TFloat;
1063 g, h, k: TFloat;
1064 R: TFloatMatrix;
1065begin
1066 px := FQuadX[0] - FQuadX[1] + FQuadX[2] - FQuadX[3];
1067 py := FQuadY[0] - FQuadY[1] + FQuadY[2] - FQuadY[3];
1068
1069 if (px = 0) and (py = 0) then
1070 begin
1071 // affine mapping
1072 FMatrix[0, 0] := FQuadX[1] - FQuadX[0];
1073 FMatrix[1, 0] := FQuadX[2] - FQuadX[1];
1074 FMatrix[2, 0] := FQuadX[0];
1075
1076 FMatrix[0, 1] := FQuadY[1] - FQuadY[0];
1077 FMatrix[1, 1] := FQuadY[2] - FQuadY[1];
1078 FMatrix[2, 1] := FQuadY[0];
1079
1080 FMatrix[0, 2] := 0;
1081 FMatrix[1, 2] := 0;
1082 FMatrix[2, 2] := 1;
1083 end
1084 else
1085 begin
1086 // projective mapping
1087 dx1 := FQuadX[1] - FQuadX[2];
1088 dx2 := FQuadX[3] - FQuadX[2];
1089 dy1 := FQuadY[1] - FQuadY[2];
1090 dy2 := FQuadY[3] - FQuadY[2];
1091 k := dx1 * dy2 - dx2 * dy1;
1092 if k <> 0 then
1093 begin
1094 k := 1 / k;
1095 g := (px * dy2 - py * dx2) * k;
1096 h := (dx1 * py - dy1 * px) * k;
1097
1098 FMatrix[0, 0] := FQuadX[1] - FQuadX[0] + g * FQuadX[1];
1099 FMatrix[1, 0] := FQuadX[3] - FQuadX[0] + h * FQuadX[3];
1100 FMatrix[2, 0] := FQuadX[0];
1101
1102 FMatrix[0, 1] := FQuadY[1] - FQuadY[0] + g * FQuadY[1];
1103 FMatrix[1, 1] := FQuadY[3] - FQuadY[0] + h * FQuadY[3];
1104 FMatrix[2, 1] := FQuadY[0];
1105
1106 FMatrix[0, 2] := g;
1107 FMatrix[1, 2] := h;
1108 FMatrix[2, 2] := 1;
1109 end
1110 else
1111 begin
1112 FillChar(FMatrix, SizeOf(FMatrix), 0);
1113 end;
1114 end;
1115
1116 // denormalize texture space (u, v)
1117 R := IdentityMatrix;
1118 R[0, 0] := 1 / (SrcRect.Right - SrcRect.Left);
1119 R[1, 1] := 1 / (SrcRect.Bottom - SrcRect.Top);
1120 FMatrix := Mult(FMatrix, R);
1121
1122 R := IdentityMatrix;
1123 R[2, 0] := -SrcRect.Left;
1124 R[2, 1] := -SrcRect.Top;
1125 FMatrix := Mult(FMatrix, R);
1126
1127 inherited;
1128end;
1129
1130procedure TProjectiveTransformation.SetX(Index: Integer; const Value: TFloat);
1131begin
1132 FQuadX[Index] := Value;
1133 Changed;
1134end;
1135
1136procedure TProjectiveTransformation.SetY(Index: Integer; const Value: TFloat);
1137begin
1138 FQuadY[Index] := Value;
1139 Changed;
1140end;
1141
1142procedure TProjectiveTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
1143 out SrcX, SrcY: TFixed);
1144var
1145 Z: TFixed;
1146 Zf: TFloat;
1147begin
1148 Z := FixedMul(FInverseFixedMatrix[0, 2], DstX) +
1149 FixedMul(FInverseFixedMatrix[1, 2], DstY) + FInverseFixedMatrix[2, 2];
1150
1151 if Z = 0 then Exit;
1152
1153 {$IFDEF UseInlining}
1154 SrcX := FixedMul(DstX, FInverseFixedMatrix[0, 0]) +
1155 FixedMul(DstY, FInverseFixedMatrix[1, 0]) + FInverseFixedMatrix[2, 0];
1156 SrcY := FixedMul(DstX, FInverseFixedMatrix[0,1]) +
1157 FixedMul(DstY, FInverseFixedMatrix[1, 1]) + FInverseFixedMatrix[2, 1];
1158 {$ELSE}
1159 inherited;
1160 {$ENDIF}
1161
1162 if Z <> FixedOne then
1163 begin
1164 EMMS;
1165 Zf := FixedOne / Z;
1166 SrcX := Round(SrcX * Zf);
1167 SrcY := Round(SrcY * Zf);
1168 end;
1169end;
1170
1171procedure TProjectiveTransformation.ReverseTransformFloat(
1172 DstX, DstY: TFloat;
1173 out SrcX, SrcY: TFloat);
1174var
1175 Z: TFloat;
1176begin
1177 EMMS;
1178 Z := FInverseMatrix[0, 2] * DstX + FInverseMatrix[1, 2] * DstY +
1179 FInverseMatrix[2, 2];
1180
1181 if Z = 0 then Exit;
1182
1183 {$IFDEF UseInlining}
1184 SrcX := DstX * FInverseMatrix[0, 0] + DstY * FInverseMatrix[1, 0] +
1185 FInverseMatrix[2, 0];
1186 SrcY := DstX * FInverseMatrix[0, 1] + DstY * FInverseMatrix[1, 1] +
1187 FInverseMatrix[2, 1];
1188 {$ELSE}
1189 inherited;
1190 {$ENDIF}
1191
1192 if Z <> 1 then
1193 begin
1194 Z := 1 / Z;
1195 SrcX := SrcX * Z;
1196 SrcY := SrcY * Z;
1197 end;
1198end;
1199
1200procedure TProjectiveTransformation.TransformFixed(SrcX, SrcY: TFixed;
1201 out DstX, DstY: TFixed);
1202var
1203 Z: TFixed;
1204 Zf: TFloat;
1205begin
1206 Z := FixedMul(FFixedMatrix[0, 2], SrcX) +
1207 FixedMul(FFixedMatrix[1, 2], SrcY) + FFixedMatrix[2, 2];
1208
1209 if Z = 0 then Exit;
1210
1211 {$IFDEF UseInlining}
1212 DstX := FixedMul(SrcX, FFixedMatrix[0, 0]) +
1213 FixedMul(SrcY, FFixedMatrix[1, 0]) + FFixedMatrix[2, 0];
1214 DstY := FixedMul(SrcX, FFixedMatrix[0, 1]) +
1215 FixedMul(SrcY, FFixedMatrix[1, 1]) + FFixedMatrix[2, 1];
1216 {$ELSE}
1217 inherited;
1218 {$ENDIF}
1219
1220 if Z <> FixedOne then
1221 begin
1222 EMMS;
1223 Zf := FixedOne / Z;
1224 DstX := Round(DstX * Zf);
1225 DstY := Round(DstY * Zf);
1226 end;
1227end;
1228
1229procedure TProjectiveTransformation.TransformFloat(SrcX, SrcY: TFloat;
1230 out DstX, DstY: TFloat);
1231var
1232 Z: TFloat;
1233begin
1234 EMMS;
1235 Z := FMatrix[0, 2] * SrcX + FMatrix[1, 2] * SrcY + FMatrix[2, 2];
1236
1237 if Z = 0 then Exit;
1238
1239 {$IFDEF UseInlining}
1240 DstX := SrcX * Matrix[0, 0] + SrcY * Matrix[1, 0] + Matrix[2, 0];
1241 DstY := SrcX * Matrix[0, 1] + SrcY * Matrix[1, 1] + Matrix[2, 1];
1242 {$ELSE}
1243 inherited;
1244 {$ENDIF}
1245
1246 if Z <> 1 then
1247 begin
1248 Z := 1 / Z;
1249 DstX := DstX * Z;
1250 DstY := DstY * Z;
1251 end;
1252end;
1253
1254
1255{ TTwirlTransformation }
1256
1257constructor TTwirlTransformation.Create;
1258begin
1259 FTwirl := 0.03;
1260end;
1261
1262function TTwirlTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
1263var
1264 Cx, Cy, R: TFloat;
1265const
1266 CPiHalf: TFloat = 0.5 * Pi;
1267begin
1268 Cx := (ASrcRect.Left + ASrcRect.Right) * 0.5;
1269 Cy := (ASrcRect.Top + ASrcRect.Bottom) * 0.5;
1270 R := Max(Cx - ASrcRect.Left, Cy - ASrcRect.Top);
1271 Result.Left := Cx - R * CPiHalf;
1272 Result.Right := Cx + R * CPiHalf;
1273 Result.Top := Cy - R * CPiHalf;
1274 Result.Bottom := Cy + R * CPiHalf;
1275end;
1276
1277procedure TTwirlTransformation.PrepareTransform;
1278begin
1279 with FSrcRect do
1280 begin
1281 Frx := (Right - Left) * 0.5;
1282 Fry := (Bottom - Top) * 0.5;
1283 end;
1284 TransformValid := True;
1285end;
1286
1287procedure TTwirlTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
1288 out SrcX, SrcY: TFloat);
1289var
1290 xf, yf, r, t: Single;
1291begin
1292 xf := DstX - Frx;
1293 yf := DstY - Fry;
1294
1295 r := GR32_Math.Hypot(xf, yf);
1296 t := ArcTan2(yf, xf) + r * FTwirl;
1297 GR32_Math.SinCos(t, yf, xf);
1298
1299 SrcX := Frx + r * xf;
1300 SrcY := Fry + r * yf;
1301end;
1302
1303procedure TTwirlTransformation.SetTwirl(const Value: TFloat);
1304begin
1305 FTwirl := Value;
1306 Changed;
1307end;
1308
1309{ TBloatTransformation }
1310
1311constructor TBloatTransformation.Create;
1312begin
1313 FBloatPower := 0.3;
1314end;
1315
1316procedure TBloatTransformation.PrepareTransform;
1317begin
1318 FPiW := (Pi / (FSrcRect.Right - FSrcRect.Left));
1319 FPiH := (Pi / (FSrcRect.Bottom - FSrcRect.Top));
1320 FBP := FBloatPower * Max(FSrcRect.Right - FSrcRect.Left, FSrcRect.Bottom - FSrcRect.Top);
1321 TransformValid := True;
1322end;
1323
1324procedure TBloatTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
1325 out SrcX, SrcY: TFloat);
1326var
1327 SinY, CosY, SinX, CosX, t: Single;
1328begin
1329 GR32_Math.SinCos(FPiH * DstY, SinY, CosY);
1330 GR32_Math.SinCos(FPiW * DstX, SinX, CosX);
1331 t := FBP * SinY * SinX;
1332 SrcX := DstX + t * CosX;
1333 SrcY := DstY + t * CosY;
1334end;
1335
1336procedure TBloatTransformation.TransformFloat(DstX, DstY: TFloat;
1337 out SrcX, SrcY: TFloat);
1338var
1339 SinY, CosY, SinX, CosX, t: Single;
1340begin
1341 GR32_Math.SinCos(-FPiH * DstY, SinY, CosY);
1342 GR32_Math.SinCos(-FPiW * DstX, SinX, CosX);
1343 t := FBP * SinY * SinX;
1344 SrcX := DstX + t * CosX;
1345 SrcY := DstY + t * CosY;
1346end;
1347
1348procedure TBloatTransformation.SetBloatPower(const Value: TFloat);
1349begin
1350 FBloatPower := Value;
1351 Changed;
1352end;
1353
1354{ TFishEyeTransformation }
1355
1356procedure TFishEyeTransformation.PrepareTransform;
1357begin
1358 with FSrcRect do
1359 begin
1360 Frx := (Right - Left) * 0.5;
1361 Fry := (Bottom - Top) * 0.5;
1362 if Frx <= Fry then
1363 begin
1364 FMinR := Frx;
1365 Sx := 1;
1366 Sy:= Frx / Fry;
1367 end
1368 else
1369 begin
1370 FMinR := Fry;
1371 Sx:= Fry / Frx;
1372 Sy := 1;
1373 end;
1374 Fsr := 1 / FMinR;
1375 Faw := ArcSin(Constrain(FMinR * Fsr, -1, 1));
1376 if Faw <> 0 then Faw := 1 / Faw;
1377 Faw := Faw * FMinR
1378 end;
1379 TransformValid := True;
1380end;
1381
1382procedure TFishEyeTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
1383 out SrcX, SrcY: TFloat);
1384var
1385 d, Xrx, Yry: TFloat;
1386begin
1387 Yry := (DstY - Fry) * sy;
1388 Xrx := (DstX - Frx) * sx;
1389 d := GR32_Math.Hypot(Xrx, Yry);
1390 if (d < FMinR) and (d > 0) then
1391 begin
1392 d := ArcSin(d * Fsr) * Faw / d;
1393 SrcX := Frx + Xrx * d;
1394 SrcY := Fry + Yry * d;
1395 end
1396 else
1397 begin
1398 SrcX := DstX;
1399 SrcY := DstY;
1400 end;
1401end;
1402
1403
1404{ TPolarTransformation }
1405
1406procedure TPolarTransformation.PrepareTransform;
1407begin
1408 Sx := SrcRect.Right - SrcRect.Left;
1409 Sy := SrcRect.Bottom - SrcRect.Top;
1410 Cx := (DstRect.Left + DstRect.Right) * 0.5;
1411 Cy := (DstRect.Top + DstRect.Bottom) * 0.5;
1412 Dx := DstRect.Right - Cx;
1413 Dy := DstRect.Bottom - Cy;
1414
1415 Rt := (1 / (PI * 2)) * Sx;
1416
1417 Rt2 := Sx;
1418 if Rt2 <> 0 then Rt2 := 1 / Sx else Rt2 := 0.00000001;
1419 Rt2 := Rt2 * 2 * Pi;
1420
1421 Rr := Sy;
1422 if Rr <> 0 then Rr := 1 / Rr else Rr := 0.00000001;
1423
1424 Rcx := Cx;
1425 if Rcx <> 0 then Rcx := 1 / Rcx else Rcx := 0.00000001;
1426
1427 Rcy := Cy;
1428 if Rcy <> 0 then Rcy := 1 / Rcy else Rcy := 0.00000001;
1429
1430 TransformValid := True;
1431end;
1432
1433procedure TPolarTransformation.SetDstRect(const Value: TFloatRect);
1434begin
1435 FDstRect := Value;
1436 Changed;
1437end;
1438
1439procedure TPolarTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
1440 DstY: TFloat);
1441var
1442 R, Theta, S, C: TFloat;
1443begin
1444 Theta := (SrcX - SrcRect.Left) * Rt2 + Phase;
1445 R := (SrcY - SrcRect.Bottom) * Rr;
1446 GR32_Math.SinCos(Theta, S, C);
1447
1448 DstX := Dx * R * C + Cx;
1449 DstY := Dy * R * S + Cy;
1450end;
1451
1452procedure TPolarTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
1453 out SrcX, SrcY: TFloat);
1454const
1455 PI2 = 2 * PI;
1456var
1457 Dcx, Dcy, Theta: TFloat;
1458begin
1459 Dcx := (DstX - Cx) * Rcx;
1460 Dcy := (DstY - Cy) * Rcy;
1461
1462 Theta := ArcTan2(Dcy, Dcx) + Pi - Phase;
1463 if Theta < 0 then Theta := Theta + PI2;
1464
1465 SrcX := SrcRect.Left + Theta * Rt;
1466 SrcY := SrcRect.Bottom - GR32_Math.Hypot(Dcx, Dcy) * Sy;
1467end;
1468
1469
1470procedure TPolarTransformation.SetPhase(const Value: TFloat);
1471begin
1472 FPhase := Value;
1473 Changed;
1474end;
1475
1476
1477{ TPathTransformation }
1478
1479destructor TPathTransformation.Destroy;
1480begin
1481 FTopHypot := nil;
1482 FBottomHypot := nil;
1483 inherited;
1484end;
1485
1486procedure TPathTransformation.PrepareTransform;
1487var
1488 I: Integer;
1489 L, DDist: TFloat;
1490begin
1491 if not (Assigned(FTopCurve) and Assigned(FBottomCurve)) then
1492 raise ETransformError.Create(RCStrTopBottomCurveNil);
1493
1494 SetLength(FTopHypot, Length(FTopCurve));
1495 SetLength(FBottomHypot, Length(FBottomCurve));
1496
1497 L := 0;
1498 for I := 0 to High(FTopCurve) - 1 do
1499 begin
1500 FTopHypot[I].Dist := L;
1501 with FTopCurve[I + 1] do
1502 L := L + GR32_Math.Hypot(FTopCurve[I].X - X, FTopCurve[I].Y - Y);
1503 end;
1504 FTopLength := L;
1505
1506 for I := 1 to High(FTopCurve) do
1507 with FTopHypot[I] do
1508 begin
1509 DDist := Dist - FTopHypot[I - 1].Dist;
1510 if DDist <> 0 then
1511 RecDist := 1 / DDist
1512 else if I > 1 then
1513 RecDist := FTopHypot[I - 1].RecDist
1514 else
1515 RecDist := 0;
1516 end;
1517
1518 L := 0;
1519 for I := 0 to High(FBottomCurve) - 1 do
1520 begin
1521 FBottomHypot[I].Dist := L;
1522 with FBottomCurve[I + 1] do
1523 L := L + GR32_Math.Hypot(FBottomCurve[I].X - X, FBottomCurve[I].Y - Y);
1524 end;
1525 FBottomLength := L;
1526
1527 for I := 1 to High(FBottomCurve) do
1528 with FBottomHypot[I] do
1529 begin
1530 DDist := Dist - FBottomHypot[I - 1].Dist;
1531 if DDist <> 0 then
1532 RecDist := 1 / DDist
1533 else if I > 1 then
1534 RecDist := FBottomHypot[I - 1].RecDist
1535 else
1536 RecDist := 0;
1537 end;
1538
1539 rdx := 1 / (SrcRect.Right - SrcRect.Left);
1540 rdy := 1 / (SrcRect.Bottom - SrcRect.Top);
1541
1542 TransformValid := True;
1543end;
1544
1545procedure TPathTransformation.SetBottomCurve(const Value: TArrayOfFloatPoint);
1546begin
1547 FBottomCurve := Value;
1548 Changed;
1549end;
1550
1551procedure TPathTransformation.SetTopCurve(const Value: TArrayOfFloatPoint);
1552begin
1553 FTopCurve := Value;
1554 Changed;
1555end;
1556
1557procedure TPathTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
1558 DstY: TFloat);
1559var
1560 I, H: Integer;
1561 X, Y, fx, dx, dy, r, Tx, Ty, Bx, By: TFloat;
1562begin
1563 X := (SrcX - SrcRect.Left) * rdx;
1564 Y := (SrcY - SrcRect.Top) * rdy;
1565
1566 fx := X * FTopLength;
1567 I := 1;
1568 H := High(FTopHypot);
1569 while (FTopHypot[I].Dist < fx) and (I < H) do Inc(I);
1570
1571
1572 with FTopHypot[I] do
1573 r := (Dist - fx) * RecDist;
1574
1575 dx := (FTopCurve[I - 1].X - FTopCurve[I].X);
1576 dy := (FTopCurve[I - 1].Y - FTopCurve[I].Y);
1577 Tx := FTopCurve[I].X + r * dx;
1578 Ty := FTopCurve[I].Y + r * dy;
1579
1580 fx := X * FBottomLength;
1581 I := 1;
1582 H := High(FBottomHypot);
1583 while (FBottomHypot[I].Dist < fx) and (I < H) do Inc(I);
1584
1585
1586 with FBottomHypot[I] do
1587 r := (Dist - fx) * RecDist;
1588
1589 dx := (FBottomCurve[I - 1].X - FBottomCurve[I].X);
1590 dy := (FBottomCurve[I - 1].Y - FBottomCurve[I].Y);
1591 Bx := FBottomCurve[I].X + r * dx;
1592 By := FBottomCurve[I].Y + r * dy;
1593
1594 DstX := Tx + Y * (Bx - Tx);
1595 DstY := Ty + Y * (By - Ty);
1596end;
1597
1598
1599{ TDisturbanceTransformation }
1600
1601function TDisturbanceTransformation.GetTransformedBounds(
1602 const ASrcRect: TFloatRect): TFloatRect;
1603begin
1604 Result := ASrcRect;
1605 InflateRect(Result, 0.5 * FDisturbance, 0.5 * FDisturbance);
1606end;
1607
1608procedure TDisturbanceTransformation.ReverseTransformFloat(DstX,
1609 DstY: TFloat; out SrcX, SrcY: TFloat);
1610begin
1611 SrcX := DstX + (Random - 0.5) * FDisturbance;
1612 SrcY := DstY + (Random - 0.5) * FDisturbance;
1613end;
1614
1615procedure TDisturbanceTransformation.SetDisturbance(const Value: TFloat);
1616begin
1617 FDisturbance := Value;
1618 Changed;
1619end;
1620
1621{ TRemapTransformation }
1622
1623constructor TRemapTransformation.Create;
1624begin
1625 inherited;
1626 FScalingFixed := FixedPoint(1, 1);
1627 FScalingFloat := FloatPoint(1, 1);
1628 FOffset := FloatPoint(0,0);
1629 FVectorMap := TVectorMap.Create;
1630 //Ensuring initial setup to avoid exceptions
1631 FVectorMap.SetSize(1, 1);
1632end;
1633
1634destructor TRemapTransformation.Destroy;
1635begin
1636 FVectorMap.Free;
1637 inherited;
1638end;
1639
1640function TRemapTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
1641const
1642 InfRect: TFloatRect = (Left: -Infinity; Top: -Infinity; Right: Infinity; Bottom: Infinity);
1643begin
1644 // We can't predict the ultimate bounds without transforming each vector in
1645 // the vector map, return the absolute biggest possible transformation bounds
1646 Result := InfRect;
1647end;
1648
1649function TRemapTransformation.HasTransformedBounds: Boolean;
1650begin
1651 Result := False;
1652end;
1653
1654procedure TRemapTransformation.PrepareTransform;
1655begin
1656 if IsRectEmpty(SrcRect) then raise Exception.Create(RCStrSrcRectIsEmpty);
1657 if IsRectEmpty(FMappingRect) then raise Exception.Create(RCStrMappingRectIsEmpty);
1658 with SrcRect do
1659 begin
1660 FSrcTranslationFloat.X := Left;
1661 FSrcTranslationFloat.Y := Top;
1662 FSrcScaleFloat.X := (Right - Left) / (FVectorMap.Width - 1);
1663 FSrcScaleFloat.Y := (Bottom - Top) / (FVectorMap.Height - 1);
1664 FSrcTranslationFixed := FixedPoint(FSrcTranslationFloat);
1665 FSrcScaleFixed := FixedPoint(FSrcScaleFloat);
1666 end;
1667
1668 with FMappingRect do
1669 begin
1670 FDstTranslationFloat.X := Left;
1671 FDstTranslationFloat.Y := Top;
1672 FDstScaleFloat.X := (FVectorMap.Width - 1) / (Right - Left);
1673 FDstScaleFloat.Y := (FVectorMap.Height - 1) / (Bottom - Top);
1674 FCombinedScalingFloat.X := FDstScaleFloat.X * FScalingFloat.X;
1675 FCombinedScalingFloat.Y := FDstScaleFloat.Y * FScalingFloat.Y;
1676 FCombinedScalingFixed := FixedPoint(FCombinedScalingFloat);
1677 FDstTranslationFixed := FixedPoint(FDstTranslationFloat);
1678 FDstScaleFixed := FixedPoint(FDstScaleFloat);
1679 end;
1680 TransformValid := True;
1681end;
1682
1683procedure TRemapTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
1684 out SrcX, SrcY: TFixed);
1685begin
1686 with FVectorMap.FixedVectorX[DstX - FOffsetFixed.X, DstY - FOffsetFixed.Y] do
1687 begin
1688 DstX := DstX - FDstTranslationFixed.X;
1689 DstX := FixedMul(DstX , FDstScaleFixed.X);
1690 DstX := DstX + FixedMul(X, FCombinedScalingFixed.X);
1691 DstX := FixedMul(DstX, FSrcScaleFixed.X);
1692 SrcX := DstX + FSrcTranslationFixed.X;
1693
1694 DstY := DstY - FDstTranslationFixed.Y;
1695 DstY := FixedMul(DstY, FDstScaleFixed.Y);
1696 DstY := DstY + FixedMul(Y, FCombinedScalingFixed.Y);
1697 DstY := FixedMul(DstY, FSrcScaleFixed.Y);
1698 SrcY := DstY + FSrcTranslationFixed.Y;
1699 end;
1700end;
1701
1702procedure TRemapTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
1703 out SrcX, SrcY: TFloat);
1704begin
1705 with FVectorMap.FloatVectorF[DstX - FOffset.X, DstY - FOffset.Y] do
1706 begin
1707 DstX := DstX - FDstTranslationFloat.X;
1708 DstY := DstY - FDstTranslationFloat.Y;
1709 DstX := DstX * FDstScaleFloat.X;
1710 DstY := DstY * FDstScaleFloat.Y;
1711
1712 DstX := DstX + X * FCombinedScalingFloat.X;
1713 DstY := DstY + Y * FCombinedScalingFloat.Y;
1714
1715 DstX := DstX * FSrcScaleFloat.X;
1716 DstY := DstY * FSrcScaleFloat.Y;
1717 SrcX := DstX + FSrcTranslationFloat.X;
1718 SrcY := DstY + FSrcTranslationFloat.Y;
1719 end;
1720end;
1721
1722procedure TRemapTransformation.ReverseTransformInt(DstX, DstY: Integer;
1723 out SrcX, SrcY: Integer);
1724begin
1725 with FVectorMap.FixedVector[DstX - FOffsetInt.X, DstY - FOffsetInt.Y] do
1726 begin
1727 DstX := DstX * FixedOne - FDstTranslationFixed.X;
1728 DstY := DstY * FixedOne - FDstTranslationFixed.Y;
1729 DstX := FixedMul(DstX, FDstScaleFixed.X);
1730 DstY := FixedMul(DstY, FDstScaleFixed.Y);
1731
1732 DstX := DstX + FixedMul(X, FCombinedScalingFixed.X);
1733 DstY := DstY + FixedMul(Y, FCombinedScalingFixed.Y);
1734
1735 DstX := FixedMul(DstX, FSrcScaleFixed.X);
1736 DstY := FixedMul(DstY, FSrcScaleFixed.Y);
1737 SrcX := FixedRound(DstX + FSrcTranslationFixed.X);
1738 SrcY := FixedRound(DstY + FSrcTranslationFixed.Y);
1739 end;
1740end;
1741
1742procedure TRemapTransformation.Scale(Sx, Sy: TFloat);
1743begin
1744 FScalingFixed.X := Fixed(Sx);
1745 FScalingFixed.Y := Fixed(Sy);
1746 FScalingFloat.X := Sx;
1747 FScalingFloat.Y := Sy;
1748 Changed;
1749end;
1750
1751procedure TRemapTransformation.SetMappingRect(Rect: TFloatRect);
1752begin
1753 FMappingRect := Rect;
1754 Changed;
1755end;
1756
1757procedure TRemapTransformation.SetOffset(const Value: TFloatVector);
1758begin
1759 FOffset := Value;
1760 FOffsetInt := Point(Value);
1761 FOffsetFixed := FixedPoint(Value);
1762 Changed;
1763end;
1764
1765procedure RasterizeTransformation(Vectormap: TVectormap;
1766 Transformation: TTransformation; DstRect: TRect;
1767 CombineMode: TVectorCombineMode = vcmAdd;
1768 CombineCallback: TVectorCombineEvent = nil);
1769var
1770 I, J: Integer;
1771 P, Q, Progression: TFixedVector;
1772 ProgressionX, ProgressionY: TFixed;
1773 MapPtr: PFixedPointArray;
1774begin
1775 GR32.IntersectRect(DstRect, VectorMap.BoundsRect, DstRect);
1776 if GR32.IsRectEmpty(DstRect) then Exit;
1777
1778 if not TTransformationAccess(Transformation).TransformValid then
1779 TTransformationAccess(Transformation).PrepareTransform;
1780
1781 case CombineMode of
1782 vcmAdd:
1783 begin
1784 with DstRect do
1785 for I := Top to Bottom - 1 do
1786 begin
1787 MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
1788 for J := Left to Right - 1 do
1789 begin
1790 P := FixedPoint(Integer(J - Left), Integer(I - Top));
1791 Q := Transformation.ReverseTransform(P);
1792 Inc(MapPtr[J].X, Q.X - P.X);
1793 Inc(MapPtr[J].Y, Q.Y - P.Y);
1794 end;
1795 end;
1796 end;
1797 vcmReplace:
1798 begin
1799 with DstRect do
1800 for I := Top to Bottom - 1 do
1801 begin
1802 MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
1803 for J := Left to Right - 1 do
1804 begin
1805 P := FixedPoint(Integer(J - Left), Integer(I - Top));
1806 Q := Transformation.ReverseTransform(P);
1807 MapPtr[J].X := Q.X - P.X;
1808 MapPtr[J].Y := Q.Y - P.Y;
1809 end;
1810 end;
1811 end;
1812 else // vcmCustom
1813 ProgressionX := Fixed(1 / (DstRect.Right - DstRect.Left - 1));
1814 ProgressionY := Fixed(1 / (DstRect.Bottom - DstRect.Top - 1));
1815 Progression.Y := 0;
1816 with DstRect do for I := Top to Bottom - 1 do
1817 begin
1818 Progression.X := 0;
1819 MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
1820 for J := Left to Right - 1 do
1821 begin
1822 P := FixedPoint(Integer(J - Left), Integer(I - Top));
1823 Q := Transformation.ReverseTransform(P);
1824 Q.X := Q.X - P.X;
1825 Q.Y := Q.Y - P.Y;
1826 CombineCallback(Q, Progression, MapPtr[J]);
1827
1828 Inc(Progression.X, ProgressionX);
1829 end;
1830 Inc(Progression.Y, ProgressionY);
1831 end;
1832 end;
1833end;
1834
1835{ Matrix conversion routines }
1836
1837function FixedMatrix(const FloatMatrix: TFloatMatrix): TFixedMatrix;
1838begin
1839 Result[0,0] := Round(FloatMatrix[0,0] * FixedOne);
1840 Result[0,1] := Round(FloatMatrix[0,1] * FixedOne);
1841 Result[0,2] := Round(FloatMatrix[0,2] * FixedOne);
1842 Result[1,0] := Round(FloatMatrix[1,0] * FixedOne);
1843 Result[1,1] := Round(FloatMatrix[1,1] * FixedOne);
1844 Result[1,2] := Round(FloatMatrix[1,2] * FixedOne);
1845 Result[2,0] := Round(FloatMatrix[2,0] * FixedOne);
1846 Result[2,1] := Round(FloatMatrix[2,1] * FixedOne);
1847 Result[2,2] := Round(FloatMatrix[2,2] * FixedOne);
1848end;
1849
1850function FloatMatrix(const FixedMatrix: TFixedMatrix): TFloatMatrix;
1851begin
1852 Result[0,0] := FixedMatrix[0,0] * FixedToFloat;
1853 Result[0,1] := FixedMatrix[0,1] * FixedToFloat;
1854 Result[0,2] := FixedMatrix[0,2] * FixedToFloat;
1855 Result[1,0] := FixedMatrix[1,0] * FixedToFloat;
1856 Result[1,1] := FixedMatrix[1,1] * FixedToFloat;
1857 Result[1,2] := FixedMatrix[1,2] * FixedToFloat;
1858 Result[2,0] := FixedMatrix[2,0] * FixedToFloat;
1859 Result[2,1] := FixedMatrix[2,1] * FixedToFloat;
1860 Result[2,2] := FixedMatrix[2,2] * FixedToFloat;
1861end;
1862
1863{CPU target and feature Function templates}
1864
1865const
1866 FID_DETERMINANT32 = 0;
1867 FID_DETERMINANT64 = 1;
1868
1869{Complete collection of unit templates}
1870
1871var
1872 Registry: TFunctionRegistry;
1873
1874procedure RegisterBindings;
1875begin
1876 Registry := NewRegistry('GR32_Transforms bindings');
1877 Registry.RegisterBinding(FID_DETERMINANT32, @@DET32);
1878
1879 Registry.Add(FID_DETERMINANT32, @DET32_Pas, []);
1880 {$IFNDEF PUREPASCAL}
1881 Registry.Add(FID_DETERMINANT32, @DET32_ASM, []);
1882// Registry.Add(FID_DETERMINANT32, @DET32_SSE2, [ciSSE2]);
1883 {$ENDIF}
1884
1885 Registry.RegisterBinding(FID_DETERMINANT64, @@DET64);
1886
1887 Registry.Add(FID_DETERMINANT64, @DET64_Pas, []);
1888 {$IFNDEF PUREPASCAL}
1889 Registry.Add(FID_DETERMINANT64, @DET64_ASM, []);
1890// Registry.Add(FID_DETERMINANT64, @DET64_SSE2, [ciSSE2]);
1891 {$ENDIF}
1892
1893 Registry.RebindAll;
1894end;
1895
1896initialization
1897 RegisterBindings;
1898
1899end.
Note: See TracBrowser for help on using the repository browser.