CommonUtils.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:9k
- unit CommonUtils;
- //---------------------------------------------------------------------------
- interface
- //---------------------------------------------------------------------------
- uses
- Types, Classes, SysUtils, Math;
- //---------------------------------------------------------------------------
- // Returns the next power of two of the specified value.
- //---------------------------------------------------------------------------
- function NextPowerOfTwo(Value: Integer): Integer;
- //---------------------------------------------------------------------------
- // The routines 'IsPowerOfTwo', 'CeilPowerOfTwo' and 'FloorPowerOfTwo' are
- // converted from published code on FlipCode.com by Sebastian Schuberth.
- //---------------------------------------------------------------------------
- //---------------------------------------------------------------------------
- // Determines whether the specified value is a power of two.
- //---------------------------------------------------------------------------
- function IsPowerOfTwo(Value: Integer): Boolean;
- //---------------------------------------------------------------------------
- // The least power of two greater than or equal to the specified value.
- // Note that for Value = 0 and for Value > 2147483648 the result is 0.
- //---------------------------------------------------------------------------
- function CeilPowerOfTwo(Value: Integer): Integer;
- //---------------------------------------------------------------------------
- // The greatest power of two less than or equal to the specified value.
- // Note that for Value = 0 the result is 0.
- //---------------------------------------------------------------------------
- function FloorPowerOfTwo(Value: Integer): Integer;
- //---------------------------------------------------------------------------
- // Retreives a string representing quanity in kibibytes or mebibytes.
- //---------------------------------------------------------------------------
- function SizeToStr(Value: Integer): string;
- //---------------------------------------------------------------------------
- // Retreives the size of the specified file in bytes.
- //---------------------------------------------------------------------------
- function FileSize(Filename: string): Integer;
- //---------------------------------------------------------------------------
- // Determines the total size of bytes of the specified file list.
- //---------------------------------------------------------------------------
- function SizeOfFiles(List: TStrings): Integer;
- //---------------------------------------------------------------------------
- // Determines how many pixels are wasted if the specific number of patterns
- // is placed onto one or several textures with the given size.
- //---------------------------------------------------------------------------
- function TexWastedSpace(const PatternSize, TextureSize: TPoint;
- PatternCount: Integer; out TextureCount: Integer): Integer;
- //---------------------------------------------------------------------------
- // Attempts to find the best texture size to match the specified pattern
- // amount and dimensions. The heuristics try to optimize for performance
- // first, then minimize waste and finally, gives preference to textures
- // with less anisotropy (likes square textures).
- //---------------------------------------------------------------------------
- procedure BestTexSize(const PatternSize: TPoint; PatternCount: Integer;
- out TextureSize: TPoint);
- //---------------------------------------------------------------------------
- implementation
- //---------------------------------------------------------------------------
- function NextPowerOfTwo(Value: Integer): Integer;
- begin
- Result:= 1;
- asm
- xor ecx, ecx
- bsr ecx, Value
- inc ecx
- shl Result, cl
- end;
- end;
- //---------------------------------------------------------------------------
- function IsPowerOfTwo(Value: Integer): Boolean;
- begin
- Result:= (Value >= 1)and((Value and (Value - 1)) = 0);
- end;
- //---------------------------------------------------------------------------
- function CeilPowerOfTwo(Value: Integer): Integer; register;
- asm
- mov ecx, eax
- xor eax, eax
- dec ecx
- bsr ecx, ecx
- cmovz ecx, eax
- setnz al
- inc eax
- shl eax, cl
- end;
- //---------------------------------------------------------------------------
- function FloorPowerOfTwo(Value: Integer): Integer;
- asm
- xor eax, eax
- bsr ecx, ecx
- setnz al
- shl eax, cl
- end;
- //---------------------------------------------------------------------------
- function SizeToStr(Value: Integer): string;
- var
- v: Real;
- begin
- if (Value < 1024) then
- begin
- Result:= IntToStr(Value) + ' bytes';
- Exit;
- end;
- v:= Value / 1024.0;
- if (v < 8192) then
- begin
- Result:= FormatFloat('#,#.#', v) + ' KiB';
- Exit;
- end;
- v:= v / 1024.0;
- Result:= FormatFloat('#,#.#', v) + ' MiB';
- end;
- //---------------------------------------------------------------------------
- function FileSize(Filename: string): Integer;
- var
- Stream: TFileStream;
- begin
- Result:= 0;
- try
- Stream:= TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone);
- except
- Exit;
- end;
- try
- Result:= Stream.Size;
- finally
- Stream.Free();
- end;
- end;
- //---------------------------------------------------------------------------
- function SizeOfFiles(List: TStrings): Integer;
- var
- i, Size: Integer;
- begin
- Size:= 0;
- for i:= 0 to List.Count - 1 do
- Inc(Size, FileSize(List[i]));
- Result:= Size;
- end;
- //---------------------------------------------------------------------------
- function TexWastedSpace(const PatternSize, TextureSize: TPoint;
- PatternCount: Integer; out TextureCount: Integer): Integer;
- var
- UsedWidth : Integer;
- UsedHeight : Integer;
- AvailablePatterns: Integer;
- PatternsInTexture: Integer;
- Wasted : Integer;
- WastedWidth : Integer;
- WastedHeight : Integer;
- WastedCorner : Integer;
- WastedPatterns : Integer;
- begin
- UsedWidth := (TextureSize.X div PatternSize.X) * PatternSize.X;
- UsedHeight:= (TextureSize.Y div PatternSize.Y) * PatternSize.Y;
- // how many patterns fit in one texture?
- PatternsInTexture:= ((TextureSize.X div PatternSize.X) *
- (TextureSize.Y div PatternSize.Y));
- // how many textures are needed to hold all patterns
- if (PatternsInTexture > 0) then
- TextureCount:= Ceil(PatternCount / PatternsInTexture)
- else TextureCount:= 0;
- // patterns in these textures
- AvailablePatterns:= TextureCount * PatternsInTexture;
- WastedWidth := (TextureSize.X - UsedWidth) * TextureSize.Y;
- WastedHeight := (TextureSize.Y - UsedHeight) * TextureSize.X;
- WastedCorner := (TextureSize.X - UsedWidth) * (TextureSize.Y - UsedHeight);
- WastedPatterns:= (AvailablePatterns - PatternCount) * PatternSize.X * PatternSize.Y;
- // space wasted in ONE texture
- Wasted:= WastedWidth + WastedHeight - WastedCorner;
- // space wasted in ALL textures and missing patterns
- Result:= (Wasted * TextureCount) + WastedPatterns;
- end;
- //---------------------------------------------------------------------------
- procedure BestTexSize(const PatternSize: TPoint; PatternCount: Integer;
- out TextureSize: TPoint);
- const
- MaxSize: TPoint = (X: 512; Y: 512);
- var
- MinSize: TPoint;
- Wasted : Integer;
- Attempt: TPoint;
- TexCount: Integer;
- NewCount: Integer;
- NewWaste: Integer;
- Delta : Integer;
- NewDelta: Integer;
- begin
- // (1) Minimal texture size.
- MinSize:= PatternSize;
- if (not IsPowerOfTwo(MinSize.X)) then
- MinSize.X:= NextPowerOfTwo(PatternSize.X);
- if (not IsPowerOfTwo(MinSize.Y)) then
- MinSize.Y:= NextPowerOfTwo(PatternSize.Y);
- // (2) If it's not within limits -> just use the minimal size.
- if (MinSize.X > MaxSize.X)or(MinSize.Y > MaxSize.Y) then
- begin
- TextureSize:= MinSize;
- Exit;
- end;
- // (3) Assume we are using maximum texture size.
- Wasted:= TexWastedSpace(PatternSize, MaxSize, PatternCount, TexCount);
- TextureSize:= MaxSize;
- Delta:= Abs(MaxSize.X - MaxSize.Y);
- Attempt.Y:= MaxSize.Y;
- while (Attempt.Y >= MinSize.Y) do
- begin
- Attempt.X:= MaxSize.X;
- while (Attempt.X >= MinSize.X) do
- begin
- NewWaste:= TexWastedSpace(PatternSize, Attempt, PatternCount, NewCount);
- NewDelta:= Abs(Attempt.X - Attempt.Y);
- if (NewCount < TexCount)or((NewCount = TexCount)and(NewWaste < Wasted))or
- ((NewCount = TexCount)and(NewWaste = Wasted)and(NewDelta < Delta)) then
- begin
- TextureSize:= Attempt;
- Wasted := NewWaste;
- TexCount:= NewCount;
- Delta := NewDelta;
- end;
- Attempt.X:= Attempt.X div 2;
- end;
- Attempt.Y:= Attempt.Y div 2;
- end;
- end;
- //---------------------------------------------------------------------------
- end.