📄 gr32_vectormaps.pas
字号:
unit GR32_VectorMaps;
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is GR32_VectorMaps
*
* The Initial Developer of the Original Code is
* Michael Hansen <dyster_tid@hotmail.com>
*
* Portions created by the Initial Developer are Copyright (C) 2000-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mattias Andersson <mattias@centaurix.com>
*
* ***** END LICENSE BLOCK ***** *)
interface
{$I GR32.inc}
uses
{$IFDEF CLX}
Qt, Types, {$IFDEF LINUX}Libc, {$ENDIF}
{$ELSE}
Windows,
{$ENDIF}
Classes, GR32, GR32_Containers;
type
TFixedVector = TFixedPoint;
PFixedVector = ^TFixedVector;
TFloatVector = TFloatPoint;
PFloatVector = ^TFloatVector;
TArrayOfFixedVector = array of TFixedVector;
PArrayOfFixedVector = ^TArrayOfFixedVector;
TArrayOfFloatVector = array of TFloatVector;
PArrayOfFloatVector = ^TArrayOfFixedVector;
type
TVectorCombineMode = (vcmAdd, vcmReplace, vcmCustom);
TVectorCombineEvent= procedure(F, P: TFixedVector; var B: TFixedVector) of object;
TVectorMap = class(TCustomMap)
private
FVectors: TArrayOfFixedVector;
FOnVectorCombine: TVectorCombineEvent;
FVectorCombineMode: TVectorCombineMode;
function GetVectors: PFixedPointArray;
function GetFixedVector(X,Y: Integer): TFixedVector;
function GetFixedVectorS(X,Y: Integer): TFixedVector;
function GetFixedVectorX(X,Y: TFixed): TFixedVector;
function GetFixedVectorXS(X,Y: TFixed): TFixedVector;
function GetFloatVector(X,Y: Integer): TFloatVector;
function GetFloatVectorS(X,Y: Integer): TFloatVector;
function GetFloatVectorF(X,Y: Single): TFloatVector;
function GetFloatVectorFS(X,Y: Single): TFloatVector;
procedure SetFixedVector(X,Y: Integer; const Point: TFixedVector);
procedure SetFixedVectorS(X,Y: Integer; const Point: TFixedVector);
procedure SetFixedVectorX(X,Y: TFixed; const Point: TFixedVector);
procedure SetFixedVectorXS(X,Y: TFixed; const Point: TFixedVector);
procedure SetFloatVector(X,Y: Integer; const Point: TFloatVector);
procedure SetFloatVectorS(X,Y: Integer; const Point: TFloatVector);
procedure SetFloatVectorF(X,Y: Single; const Point: TFloatVector);
procedure SetFloatVectorFS(X,Y: Single; const Point: TFloatVector);
procedure SetVectorCombineMode(const Value: TVectorCombineMode);
protected
procedure ChangeSize(var Width, Height: Integer; NewWidth,
NewHeight: Integer); override;
public
destructor Destroy; override;
procedure Clear;
procedure Merge(DstLeft, DstTop: Integer; Src: TVectorMap; SrcRect: TRect);
property Vectors: PFixedPointArray read GetVectors;
function BoundsRect: TRect;
function GetTrimmedBounds: TRect;
function Empty: Boolean; override;
procedure LoadFromFile(const FileName: string);
procedure SaveToFile(const FileName: string);
property FixedVector[X, Y: Integer]: TFixedVector read GetFixedVector write SetFixedVector; default;
property FixedVectorS[X, Y: Integer]: TFixedVector read GetFixedVectorS write SetFixedVectorS;
property FixedVectorX[X, Y: TFixed]: TFixedVector read GetFixedVectorX write SetFixedVectorX;
property FixedVectorXS[X, Y: TFixed]: TFixedVector read GetFixedVectorXS write SetFixedVectorXS;
property FloatVector[X, Y: Integer]: TFloatVector read GetFloatVector write SetFloatVector;
property FloatVectorS[X, Y: Integer]: TFloatVector read GetFloatVectorS write SetFloatVectorS;
property FloatVectorF[X, Y: Single]: TFloatVector read GetFloatVectorF write SetFloatVectorF;
property FloatVectorFS[X, Y: Single]: TFloatVector read GetFloatVectorFS write SetFloatVectorFS;
published
property VectorCombineMode: TVectorCombineMode read FVectorCombineMode write SetVectorCombineMode;
property OnVectorCombine: TVectorCombineEvent read FOnVectorCombine write FOnVectorCombine;
end;
implementation
uses
GR32_Lowlevel, GR32_Blend, GR32_Transforms, GR32_Math, Math, SysUtils;
type
TTransformationAccess = class(TTransformation);
{ TVectorMap }
function CombineVectorsReg(const A, B: TFixedVector; Weight: TFixed): TFixedVector;
begin
Result.X := A.X + FixedMul(B.X - A.X, Weight);
Result.Y := A.Y + FixedMul(B.Y - A.Y, Weight);
end;
procedure CombineVectorsMem(const A: TFixedVector;var B: TFixedVector; Weight: TFixed);
begin
B.X := A.X + FixedMul(B.X - A.X, Weight);
B.Y := A.Y + FixedMul(B.Y - A.Y, Weight);
end;
function TVectorMap.BoundsRect: TRect;
begin
Result := Rect(0, 0, Width, Height);
end;
procedure TVectorMap.ChangeSize(var Width, Height: Integer;
NewWidth, NewHeight: Integer);
begin
inherited;
FVectors := nil;
Width := 0;
Height := 0;
SetLength(FVectors, NewWidth * NewHeight);
if (NewWidth > 0) and (NewHeight > 0) then
begin
if FVectors = nil then raise Exception.Create('Can''t allocate VectorMap!');
FillLongword(FVectors[0], NewWidth * NewHeight * 2, 0);
end;
Width := NewWidth;
Height := NewHeight;
end;
procedure TVectorMap.Clear;
begin
FillLongword(FVectors[0], Width * Height * 2, 0);
end;
destructor TVectorMap.Destroy;
begin
Lock;
try
SetSize(0, 0);
finally
Unlock;
end;
inherited;
end;
function TVectorMap.GetVectors: PFixedPointArray;
begin
Result := @FVectors[0];
end;
function TVectorMap.GetFloatVector(X, Y: Integer): TFloatVector;
begin
Result := FloatPoint(FVectors[X + Y * Width]);
end;
function TVectorMap.GetFloatVectorF(X, Y: Single): TFloatVector;
begin
Result := FloatPoint(GetFixedVectorX(Fixed(X), Fixed(Y)));
end;
function TVectorMap.GetFloatVectorFS(X, Y: Single): TFloatVector;
begin
Result := FloatPoint(GetFixedVectorXS(Fixed(X), Fixed(Y)));
end;
function TVectorMap.GetFloatVectorS(X, Y: Integer): TFloatVector;
begin
if (X >= 0) and (Y >= 0) and
(X < Width) and (Y < Height) then
Result := GetFloatVector(X,Y)
else
begin
Result.X := 0;
Result.Y := 0;
end;
end;
function TVectorMap.GetFixedVector(X, Y: Integer): TFixedVector;
begin
Result := FVectors[X + Y * Width];
end;
function TVectorMap.GetFixedVectorS(X, Y: Integer): TFixedVector;
begin
if (X >= 0) and (Y >= 0) and
(X < Width) and (Y < Height) then
Result := GetFixedVector(X,Y)
else
begin
Result.X := 0;
Result.Y := 0;
end;
end;
function TVectorMap.GetFixedVectorX(X, Y: TFixed): TFixedVector;
const
Next = SizeOf(TFixedVector);
var
WX,WY: TFixed;
P, W, H: Integer;
begin
WX := TFixedRec(X).Int;
WY := TFixedRec(Y).Int;
W := Width;
H := Height;
if (WX >= 0) and (WX <= W - 1) and (WY >= 0) and (WY <= H - 1) then
begin
P := Integer(@FVectors[WX + WY * W]);
if (WY = H - 1) then W := 0 else W := W * Next;
if (WX = W - 1) then H := 0 else H := Next;
WX := TFixedRec(X).Frac;
WY := TFixedRec(Y).Frac;
Result := CombineVectorsReg(CombineVectorsReg(PFixedPoint(P)^, PFixedPoint(P + H)^, WX),
CombineVectorsReg(PFixedPoint(P + W)^, PFixedPoint(P + W + H)^, WX), WY);
end else
begin
Result.X := 0;
Result.Y := 0;
end;
end;
function TVectorMap.GetFixedVectorXS(X, Y: TFixed): TFixedVector;
var
WX,WY: TFixed;
begin
WX := TFixedRec(X).Frac;
X := TFixedRec(X).Int;
WY := TFixedRec(Y).Frac;
Y := TFixedRec(Y).Int;
Result := CombineVectorsReg(CombineVectorsReg(FixedVectorS[X,Y], FixedVectorS[X + 1,Y], WX),
CombineVectorsReg(FixedVectorS[X,Y + 1], FixedVectorS[X + 1,Y + 1], WX), WY);
end;
function TVectorMap.Empty: Boolean;
begin
Result := false;
if (Width = 0) or (Height = 0) or (FVectors = nil) then Result := True;
end;
const
MeshIdent = 'yfqLhseM';
type
{TVectorMap supports the photoshop liquify mesh fileformat .msh}
TPSLiquifyMeshHeader = record
Pad0 : dword;
Ident : array [0..7] of Char;
Pad1 : dword;
Width : dword;
Height: dword;
end;
procedure TVectorMap.LoadFromFile(const FileName: string);
procedure ConvertVertices;
var
I: Integer;
begin
for I := 0 to Length(FVectors) - 1 do
FVectors[I] := FixedPoint(TFloatVector(FVectors[I])); //Not a mistake!
end;
var
Header: TPSLiquifyMeshHeader;
MeshFile: File;
begin
If FileExists(Filename) then
try
AssignFile(MeshFile, FileName);
Reset(MeshFile, 1);
BlockRead(MeshFile, Header, SizeOf(TPSLiquifyMeshHeader));
if Lowercase(String(Header.Ident)) <> Lowercase(MeshIdent) then
Exception.Create('Bad format - Photoshop .msh expected!');
with Header do
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -