source: trunk/Packages/Graphics32/GR32_VectorMaps.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 19.1 KB
Line 
1unit GR32_VectorMaps;
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 GR32_VectorMaps
24 *
25 * The Initial Developer of the Original Code is
26 * Michael Hansen <dyster_tid@hotmail.com>
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 * Mattias Andersson <mattias@centaurix.com>
33 *
34 * ***** END LICENSE BLOCK ***** *)
35
36interface
37
38{$I GR32.inc}
39
40uses
41{$IFDEF FPC}
42 {$IFDEF Windows}
43 Windows,
44 {$ENDIF}
45{$ELSE}
46 Windows,
47{$ENDIF}
48 Classes, GR32;
49
50type
51 TFixedVector = TFixedPoint;
52 PFixedVector = ^TFixedVector;
53 TFloatVector = TFloatPoint;
54 PFloatVector = ^TFloatVector;
55 TArrayOfFixedVector = array of TFixedVector;
56 PArrayOfFixedVector = ^TArrayOfFixedVector;
57 TArrayOfFloatVector = array of TFloatVector;
58 PArrayOfFloatVector = ^TArrayOfFixedVector;
59
60type
61 TVectorCombineMode = (vcmAdd, vcmReplace, vcmCustom);
62 TVectorCombineEvent= procedure(F, P: TFixedVector; var B: TFixedVector) of object;
63
64 TVectorMap = class(TCustomMap)
65 private
66 FVectors: TArrayOfFixedVector;
67 FOnVectorCombine: TVectorCombineEvent;
68 FVectorCombineMode: TVectorCombineMode;
69 function GetVectors: PFixedPointArray;
70 function GetFixedVector(X,Y: Integer): TFixedVector;
71 function GetFixedVectorS(X,Y: Integer): TFixedVector;
72 function GetFixedVectorX(X,Y: TFixed): TFixedVector;
73 function GetFixedVectorXS(X,Y: TFixed): TFixedVector;
74 function GetFloatVector(X,Y: Integer): TFloatVector;
75 function GetFloatVectorS(X,Y: Integer): TFloatVector;
76 function GetFloatVectorF(X,Y: Single): TFloatVector;
77 function GetFloatVectorFS(X,Y: Single): TFloatVector;
78 procedure SetFixedVector(X,Y: Integer; const Point: TFixedVector);
79 procedure SetFixedVectorS(X,Y: Integer; const Point: TFixedVector);
80 procedure SetFixedVectorX(X,Y: TFixed; const Point: TFixedVector);
81 procedure SetFixedVectorXS(X,Y: TFixed; const Point: TFixedVector);
82 procedure SetFloatVector(X,Y: Integer; const Point: TFloatVector);
83 procedure SetFloatVectorS(X,Y: Integer; const Point: TFloatVector);
84 procedure SetFloatVectorF(X,Y: Single; const Point: TFloatVector);
85 procedure SetFloatVectorFS(X,Y: Single; const Point: TFloatVector);
86 procedure SetVectorCombineMode(const Value: TVectorCombineMode);
87 protected
88 procedure ChangeSize(var Width, Height: Integer; NewWidth,
89 NewHeight: Integer); override;
90 public
91 destructor Destroy; override;
92
93 procedure Clear;
94 procedure Merge(DstLeft, DstTop: Integer; Src: TVectorMap; SrcRect: TRect);
95
96 property Vectors: PFixedPointArray read GetVectors;
97 function BoundsRect: TRect;
98 function GetTrimmedBounds: TRect;
99 function Empty: Boolean; override;
100 procedure LoadFromFile(const FileName: string);
101 procedure SaveToFile(const FileName: string);
102
103 property FixedVector[X, Y: Integer]: TFixedVector read GetFixedVector write SetFixedVector; default;
104 property FixedVectorS[X, Y: Integer]: TFixedVector read GetFixedVectorS write SetFixedVectorS;
105 property FixedVectorX[X, Y: TFixed]: TFixedVector read GetFixedVectorX write SetFixedVectorX;
106 property FixedVectorXS[X, Y: TFixed]: TFixedVector read GetFixedVectorXS write SetFixedVectorXS;
107
108 property FloatVector[X, Y: Integer]: TFloatVector read GetFloatVector write SetFloatVector;
109 property FloatVectorS[X, Y: Integer]: TFloatVector read GetFloatVectorS write SetFloatVectorS;
110 property FloatVectorF[X, Y: Single]: TFloatVector read GetFloatVectorF write SetFloatVectorF;
111 property FloatVectorFS[X, Y: Single]: TFloatVector read GetFloatVectorFS write SetFloatVectorFS;
112 published
113 property VectorCombineMode: TVectorCombineMode read FVectorCombineMode write SetVectorCombineMode;
114 property OnVectorCombine: TVectorCombineEvent read FOnVectorCombine write FOnVectorCombine;
115 end;
116
117implementation
118
119uses
120 GR32_Lowlevel, GR32_Math, SysUtils;
121
122resourcestring
123 RCStrCantAllocateVectorMap = 'Can''t allocate VectorMap!';
124 RCStrBadFormat = 'Bad format - Photoshop .msh expected!';
125 RCStrFileNotFound = 'File not found!';
126 RCStrSrcIsEmpty = 'Src is empty!';
127 RCStrBaseIsEmpty = 'Base is empty!';
128
129{ TVectorMap }
130
131function CombineVectorsReg(const A, B: TFixedVector; Weight: TFixed): TFixedVector;
132begin
133 Result.X := FixedCombine(Weight, B.X, A.X);
134 Result.Y := FixedCombine(Weight, B.Y, A.Y);
135end;
136
137procedure CombineVectorsMem(const A: TFixedVector;var B: TFixedVector; Weight: TFixed);
138begin
139 B.X := FixedCombine(Weight, B.X, A.X);
140 B.Y := FixedCombine(Weight, B.Y, A.Y);
141end;
142
143function TVectorMap.BoundsRect: TRect;
144begin
145 Result := Rect(0, 0, Width, Height);
146end;
147
148procedure TVectorMap.ChangeSize(var Width, Height: Integer;
149 NewWidth, NewHeight: Integer);
150begin
151 inherited;
152 FVectors := nil;
153 Width := 0;
154 Height := 0;
155 SetLength(FVectors, NewWidth * NewHeight);
156 if (NewWidth > 0) and (NewHeight > 0) then
157 begin
158 if FVectors = nil then raise Exception.Create(RCStrCantAllocateVectorMap);
159 FillLongword(FVectors[0], NewWidth * NewHeight * 2, 0);
160 end;
161 Width := NewWidth;
162 Height := NewHeight;
163end;
164
165procedure TVectorMap.Clear;
166begin
167 FillLongword(FVectors[0], Width * Height * 2, 0);
168end;
169
170destructor TVectorMap.Destroy;
171begin
172 Lock;
173 try
174 SetSize(0, 0);
175 finally
176 Unlock;
177 end;
178 inherited;
179end;
180
181function TVectorMap.GetVectors: PFixedPointArray;
182begin
183 Result := @FVectors[0];
184end;
185
186function TVectorMap.GetFloatVector(X, Y: Integer): TFloatVector;
187begin
188 Result := FloatPoint(FVectors[X + Y * Width]);
189end;
190
191function TVectorMap.GetFloatVectorF(X, Y: Single): TFloatVector;
192begin
193 Result := FloatPoint(GetFixedVectorX(Fixed(X), Fixed(Y)));
194end;
195
196function TVectorMap.GetFloatVectorFS(X, Y: Single): TFloatVector;
197begin
198 Result := FloatPoint(GetFixedVectorXS(Fixed(X), Fixed(Y)));
199end;
200
201function TVectorMap.GetFloatVectorS(X, Y: Integer): TFloatVector;
202begin
203 if (X >= 0) and (Y >= 0) and
204 (X < Width) and (Y < Height) then
205 Result := GetFloatVector(X,Y)
206 else
207 begin
208 Result.X := 0;
209 Result.Y := 0;
210 end;
211end;
212
213function TVectorMap.GetFixedVector(X, Y: Integer): TFixedVector;
214begin
215 Result := FVectors[X + Y * Width];
216end;
217
218function TVectorMap.GetFixedVectorS(X, Y: Integer): TFixedVector;
219begin
220 if (X >= 0) and (Y >= 0) and
221 (X < Width) and (Y < Height) then
222 Result := GetFixedVector(X,Y)
223 else
224 begin
225 Result.X := 0;
226 Result.Y := 0;
227 end;
228end;
229
230function TVectorMap.GetFixedVectorX(X, Y: TFixed): TFixedVector;
231const
232 Next = SizeOf(TFixedVector);
233var
234 WX,WY: TFixed;
235 W, H: Integer;
236 P: Pointer;
237begin
238 WX := TFixedRec(X).Int;
239 WY := TFixedRec(Y).Int;
240 W := Width;
241 H := Height;
242 if (WX >= 0) and (WX <= W - 1) and (WY >= 0) and (WY <= H - 1) then
243 begin
244 P := @FVectors[WX + WY * W];
245 if (WY = H - 1) then W := 0 else W := W * Next;
246 if (WX = W - 1) then H := 0 else H := Next;
247 WX := TFixedRec(X).Frac;
248 WY := TFixedRec(Y).Frac;
249 {$IFDEF HAS_NATIVEINT}
250 Result := CombineVectorsReg(CombineVectorsReg(PFixedPoint(P)^,
251 PFixedPoint(NativeUInt(P) + NativeUInt(H))^, WX), CombineVectorsReg(
252 PFixedPoint(NativeUInt(P) + NativeUInt(W))^,
253 PFixedPoint(NativeUInt(P) + NativeUInt(W + H))^, WX), WY);
254 {$ELSE}
255 Result := CombineVectorsReg(CombineVectorsReg(PFixedPoint(P)^,
256 PFixedPoint(Cardinal(P) + Cardinal(H))^, WX), CombineVectorsReg(
257 PFixedPoint(Cardinal(P) + Cardinal(W))^,
258 PFixedPoint(Cardinal(P) + Cardinal(W) + Cardinal(H))^, WX), WY);
259 {$ENDIF}
260 end else
261 begin
262 Result.X := 0;
263 Result.Y := 0;
264 end;
265end;
266
267function TVectorMap.GetFixedVectorXS(X, Y: TFixed): TFixedVector;
268var
269 WX,WY: TFixed;
270begin
271 WX := TFixedRec(X).Frac;
272 X := TFixedRec(X).Int;
273
274 WY := TFixedRec(Y).Frac;
275 Y := TFixedRec(Y).Int;
276
277 Result := CombineVectorsReg(CombineVectorsReg(FixedVectorS[X,Y], FixedVectorS[X + 1,Y], WX),
278 CombineVectorsReg(FixedVectorS[X,Y + 1], FixedVectorS[X + 1,Y + 1], WX), WY);
279end;
280
281function TVectorMap.Empty: Boolean;
282begin
283 Result := false;
284 if (Width = 0) or (Height = 0) or (FVectors = nil) then Result := True;
285end;
286
287const
288 MeshIdent = 'yfqLhseM';
289
290type
291 {TVectorMap supports the photoshop liquify mesh fileformat .msh}
292 TPSLiquifyMeshHeader = record
293 Pad0 : dword;
294 Ident : array [0..7] of Char;
295 Pad1 : dword;
296 Width : dword;
297 Height: dword;
298 end;
299
300procedure TVectorMap.LoadFromFile(const FileName: string);
301
302 procedure ConvertVertices;
303 var
304 I: Integer;
305 begin
306 for I := 0 to Length(FVectors) - 1 do
307 begin
308 //Not a mistake! Converting physical mem. directly to avoid temporary floating point buffer
309 //Do no change to PFloat.. the type is relative to the msh format.
310 FVectors[I].X := Fixed(PSingle(@FVectors[I].X)^);
311 FVectors[I].Y := Fixed(PSingle(@FVectors[I].Y)^);
312 end;
313 end;
314
315var
316 Header: TPSLiquifyMeshHeader;
317 MeshFile: File;
318begin
319 If FileExists(Filename) then
320 try
321 AssignFile(MeshFile, FileName);
322 Reset(MeshFile, 1);
323 BlockRead(MeshFile, Header, SizeOf(TPSLiquifyMeshHeader));
324 if LowerCase(string(Header.Ident)) <> LowerCase(MeshIdent) then
325 Exception.Create(RCStrBadFormat);
326 with Header do
327 begin
328 SetSize(Width, Height);
329 BlockRead(MeshFile, FVectors[0], Width * Height * SizeOf(TFixedVector));
330 ConvertVertices;
331 end;
332 finally
333 CloseFile(MeshFile);
334 end
335 else Exception.Create(RCStrFileNotFound);
336end;
337
338procedure TVectorMap.Merge(DstLeft, DstTop: Integer; Src: TVectorMap; SrcRect: TRect);
339var
340 I,J,P: Integer;
341 DstRect: TRect;
342 Progression: TFixedVector;
343 ProgressionX, ProgressionY: TFixed;
344 CombineCallback: TVectorCombineEvent;
345 DstPtr : PFixedPointArray;
346 SrcPtr : PFixedPoint;
347begin
348 if Src.Empty then Exception.Create(RCStrSrcIsEmpty);
349 if Empty then Exception.Create(RCStrBaseIsEmpty);
350 IntersectRect( SrcRect, Src.BoundsRect, SrcRect);
351
352 DstRect.Left := DstLeft;
353 DstRect.Top := DstTop;
354 DstRect.Right := DstLeft + (SrcRect.Right - SrcRect.Left);
355 DstRect.Bottom := DstTop + (SrcRect.Bottom - SrcRect.Top);
356
357 IntersectRect(DstRect, BoundsRect, DstRect);
358 if IsRectEmpty(DstRect) then Exit;
359
360 P := SrcRect.Top * Src.Width;
361 Progression.Y := - FixedOne;
362 case Src.FVectorCombineMode of
363 vcmAdd:
364 begin
365 for I := DstRect.Top to DstRect.Bottom do
366 begin
367 // Added ^ for FPC
368 DstPtr := @GetVectors^[I * Width];
369 SrcPtr := @Src.GetVectors^[SrcRect.Left + P];
370 for J := DstRect.Left to DstRect.Right do
371 begin
372 Inc(SrcPtr^.X, DstPtr[J].X);
373 Inc(SrcPtr^.Y, DstPtr[J].Y);
374 Inc(SrcPtr);
375 end;
376 Inc(P, Src.Width);
377 end;
378 end;
379 vcmReplace:
380 begin
381 for I := DstRect.Top to DstRect.Bottom do
382 begin
383 // Added ^ for FPC
384 DstPtr := @GetVectors^[I * Width];
385 SrcPtr := @Src.GetVectors^[SrcRect.Left + P];
386 for J := DstRect.Left to DstRect.Right do
387 begin
388 SrcPtr^.X := DstPtr[J].X;
389 SrcPtr^.Y := DstPtr[J].Y;
390 Inc(SrcPtr);
391 end;
392 Inc(P, Src.Width);
393 end;
394 end;
395 else
396 CombineCallback := Src.FOnVectorCombine;
397 ProgressionX := Fixed(2 / (DstRect.Right - DstRect.Left - 1));
398 ProgressionY := Fixed(2 / (DstRect.Bottom - DstRect.Top - 1));
399 for I := DstRect.Top to DstRect.Bottom do
400 begin
401 Progression.X := - FixedOne;
402 // Added ^ for FPC
403 DstPtr := @GetVectors^[I * Width];
404 SrcPtr := @Src.GetVectors^[SrcRect.Left + P];
405 for J := DstRect.Left to DstRect.Right do
406 begin
407 CombineCallback(SrcPtr^, Progression, DstPtr[J]);
408 Inc(SrcPtr);
409 Inc(Progression.X, ProgressionX);
410 end;
411 Inc(P, Src.Width);
412 Inc(Progression.Y, ProgressionY);
413 end;
414 end;
415end;
416
417procedure TVectorMap.SaveToFile(const FileName: string);
418
419 procedure ConvertVerticesX;
420 var
421 I: Integer;
422 begin
423 for I := 0 to Length(FVectors) - 1 do
424 begin
425 //Not a mistake! Converting physical mem. directly to avoid temporary floating point buffer
426 //Do no change to PFloat.. the type is relative to the msh format.
427 FVectors[I].X := Fixed(PSingle(@FVectors[I].X)^);
428 FVectors[I].Y := Fixed(PSingle(@FVectors[I].Y)^);
429 end;
430 end;
431
432 procedure ConvertVerticesF;
433 var
434 I: Integer;
435{$IFDEF COMPILERRX1}
436 f: single;
437{$ENDIF}
438 begin
439 for I := 0 to Length(FVectors) - 1 do
440 begin
441 //Not a mistake! Converting physical mem. directly to avoid temporary floating point buffer
442 //Do no change to PFloat.. the type is relative to the msh format.
443
444//Workaround for Delphi 10.1 Internal Error C6949 ...
445{$IFDEF COMPILERRX1}
446 f := FVectors[I].X * FixedToFloat;
447 FVectors[I].X := PInteger(@f)^;
448 f := FVectors[I].Y * FixedToFloat;
449 FVectors[I].Y := PInteger(@f)^;
450{$ELSE}
451 PSingle(@FVectors[I].X)^ := FVectors[I].X * FixedToFloat;
452 PSingle(@FVectors[I].Y)^ := FVectors[I].Y * FixedToFloat;
453{$ENDIF}
454 end;
455 end;
456
457var
458 Header: TPSLiquifyMeshHeader;
459 MeshFile: File;
460 Pad: Cardinal;
461begin
462 try
463 AssignFile(MeshFile, FileName);
464 Rewrite(MeshFile, 1);
465 with Header do
466 begin
467 Pad0 := $02000000;
468 Ident := MeshIdent;
469 Pad1 := $00000002;
470 Width := Self.Width;
471 Height := Self.Height;
472 end;
473 BlockWrite(MeshFile, Header, SizeOf(TPSLiquifyMeshHeader));
474 with Header do
475 begin
476 ConvertVerticesF;
477 BlockWrite(MeshFile, FVectors[0], Length(FVectors) * SizeOf(TFixedVector));
478 ConvertVerticesX;
479 end;
480 if Odd(Length(FVectors) * SizeOf(TFixedVector) - 1) then
481 begin
482 Pad := $00000000;
483 BlockWrite(MeshFile, Pad, 4);
484 BlockWrite(MeshFile, Pad, 4);
485 end;
486 finally
487 CloseFile(MeshFile);
488 end;
489end;
490
491procedure TVectorMap.SetFloatVector(X, Y: Integer; const Point: TFloatVector);
492begin
493 FVectors[X + Y * Width] := FixedPoint(Point);
494end;
495
496procedure TVectorMap.SetFloatVectorF(X, Y: Single; const Point: TFloatVector);
497begin
498 SetFixedVectorX(Fixed(X), Fixed(Y), FixedPoint(Point));
499end;
500
501procedure TVectorMap.SetFloatVectorFS(X, Y: Single; const Point: TFloatVector);
502begin
503 SetFixedVectorXS(Fixed(X), Fixed(Y), FixedPoint(Point));
504end;
505
506procedure TVectorMap.SetFloatVectorS(X, Y: Integer; const Point: TFloatVector);
507begin
508 if (X >= 0) and (X < Width) and
509 (Y >= 0) and (Y < Height) then
510 FVectors[X + Y * Width] := FixedPoint(Point);
511end;
512
513procedure TVectorMap.SetFixedVector(X, Y: Integer; const Point: TFixedVector);
514begin
515 FVectors[X + Y * Width] := Point;
516end;
517
518procedure TVectorMap.SetFixedVectorS(X, Y: Integer; const Point: TFixedVector);
519begin
520 if (X >= 0) and (X < Width) and
521 (Y >= 0) and (Y < Height) then
522 FVectors[X + Y * Width] := Point;
523end;
524
525procedure TVectorMap.SetFixedVectorX(X, Y: TFixed; const Point: TFixedVector);
526var
527 flrx, flry, celx, cely: Integer;
528 P: PFixedPoint;
529begin
530 flrx := TFixedRec(X).Frac;
531 celx := flrx xor $FFFF;
532 flry := TFixedRec(Y).Frac;
533 cely := flry xor $FFFF;
534
535 P := @FVectors[TFixedRec(X).Int + TFixedRec(Y).Int * Width];
536
537 CombineVectorsMem(Point, P^, FixedMul(celx, cely)); Inc(P);
538 CombineVectorsMem(Point, P^, FixedMul(flrx, cely)); Inc(P, Width);
539 CombineVectorsMem(Point, P^, FixedMul(flrx, flry)); Dec(P);
540 CombineVectorsMem(Point, P^, FixedMul(celx, flry));
541end;
542
543procedure TVectorMap.SetFixedVectorXS(X, Y: TFixed; const Point: TFixedVector);
544var
545 flrx, flry, celx, cely: Integer;
546 P: PFixedPoint;
547begin
548 if (X < -$10000) or (Y < -$10000) then Exit;
549
550 flrx := TFixedRec(X).Frac;
551 X := TFixedRec(X).Int;
552 flry := TFixedRec(Y).Frac;
553 Y := TFixedRec(Y).Int;
554
555 if (X >= Width) or (Y >= Height) then Exit;
556
557 celx := flrx xor $FFFF;
558 cely := flry xor $FFFF;
559 P := @FVectors[X + Y * Width];
560
561 if (X >= 0) and (Y >= 0)then
562 begin
563 CombineVectorsMem(Point, P^, FixedMul(celx, cely) ); Inc(P);
564 CombineVectorsMem(Point, P^, FixedMul(flrx, cely) ); Inc(P, Width);
565 CombineVectorsMem(Point, P^, FixedMul(flrx, flry) ); Dec(P);
566 CombineVectorsMem(Point, P^, FixedMul(celx, flry) );
567 end
568 else
569 begin
570 if (X >= 0) and (Y >= 0) then CombineVectorsMem(Point, P^, FixedMul(celx, cely)); Inc(P);
571 if (X < Width - 1) and (Y >= 0) then CombineVectorsMem(Point, P^, FixedMul(flrx, cely)); Inc(P, Width);
572 if (X < Width - 1) and (Y < Height - 1) then CombineVectorsMem(Point, P^, FixedMul(flrx, flry)); Dec(P);
573 if (X >= 0) and (Y < Height - 1) then CombineVectorsMem(Point, P^, FixedMul(celx, flry));
574 end;
575end;
576
577procedure TVectorMap.SetVectorCombineMode(const Value: TVectorCombineMode);
578begin
579 if FVectorCombineMode <> Value then
580 begin
581 FVectorCombineMode := Value;
582 Changed;
583 end;
584end;
585
586function TVectorMap.GetTrimmedBounds: TRect;
587var
588 J: Integer;
589 VectorPtr : PFixedVector;
590label
591 TopDone, BottomDone, LeftDone, RightDone;
592
593begin
594 with Result do
595 begin
596 //Find Top
597 Top := 0;
598 VectorPtr := @Vectors[Top];
599 repeat
600 if Int64(VectorPtr^) <> 0 then goto TopDone;
601 Inc(VectorPtr);
602 Inc(Top);
603 until Top = Self.Width * Self.Height;
604
605 TopDone: Top := Top div Self.Width;
606
607 //Find Bottom
608 Bottom := Self.Width * Self.Height - 1;
609 VectorPtr := @Vectors[Bottom];
610 repeat
611 if Int64(VectorPtr^) <> 0 then goto BottomDone;
612 Dec(VectorPtr);
613 Dec(Bottom);
614 until Bottom < 0;
615
616 BottomDone: Bottom := Bottom div Self.Width - 1;
617
618 //Find Left
619 Left := 0;
620 repeat
621 J := Top;
622 repeat
623 if Int64(FixedVector[Left, J]) <> 0 then goto LeftDone;
624 Inc(J);
625 until J >= Bottom;
626 Inc(Left)
627 until Left >= Self.Width;
628
629 LeftDone:
630
631 //Find Right
632 Right := Self.Width - 1;
633 repeat
634 J := Bottom;
635 repeat
636 if Int64(FixedVector[Right, J]) <> 0 then goto RightDone;
637 Dec(J);
638 until J <= Top;
639 Dec(Right)
640 until Right <= Left;
641
642 end;
643 RightDone:
644 if IsRectEmpty(Result) then
645 Result := Rect(0, 0, 0, 0);
646end;
647
648end.
Note: See TracBrowser for help on using the repository browser.