////////////////////////////////////////////////////////////////////////////////
//Generic delphi runtime v3.6 for Spine animation tool //
//Runtime port by cjk (hzi1980@163.com) //
////////////////////////////////////////////////////////////////////////////////
unit spine.core.atlas;
interface
uses
System.Classes, System.SysUtils, System.Generics.Collections, System.TypInfo,
System.Math, spine.types, spine.classes;
type
TSpineAtlas = class(IAtlas)
private type
TupleStringArray = array [0..3] of string;
private
FPages: TObjectList<TAtlasPage>;
FRegions: TObjectDictionary<string, TAtlasRegion>;
FTextureLoader: ITextureLoader;
procedure Load(const AStream: TStream);
public
constructor Create(const AStream: TStream; const ATextureLoader: ITextureLoader);
destructor Destroy; override;
end;
implementation
{ TSpineAtlas }
constructor TSpineAtlas.Create(const AStream: TStream;
const ATextureLoader: ITextureLoader);
begin
inherited Create;
FPages:= TObjectList<TAtlasPage>.Create;
FRegions:= TObjectDictionary<string,TAtlasRegion>.Create([doOwnsValues]);
FTextureLoader:= ATextureLoader;
Load(AStream);
end;
destructor TSpineAtlas.Destroy;
begin
FPages.Free;
FRegions.Free;
inherited;
end;
procedure TSpineAtlas.Load(const AStream: TStream);
var
EndOf: Boolean;
function ReadLn(): string;
var
b, b1: Byte;
begin
Result:= '';
if AStream.Position = AStream.Size then
begin
EndOf:= True;
Exit;
end;
//
while AStream.Position < AStream.Size do
begin
{$Hints off}
AStream.Read(b, 1);
{$Hints on}
if (b <> $D) and (b <> $A) then
Result:= Result + AnsiChar(Chr(b))
else
Break;
end;
//
if AStream.Position < AStream.Size then
{$Hints off}
AStream.Read(b1, 1)
{$Hints on}
else Exit;
//
while ((b1 = $D) or (b1 = $A)) and (b1 <> b) and (AStream.Position < AStream.Size) do
AStream.Read(b1, 1);
//
if AStream.Position < AStream.Size then
AStream.Position:= AStream.Position - 1;
end;
function ReadTuple(out ATuple: TupleStringArray): Integer;
var
ln: string;
colon, i, lastMatch, comma: Integer;
begin
ln:= Trim(ReadLn);
colon:= ln.IndexOf(':');
if colon = -1 then raise Exception.CreateFmt('Invalid line:%s',[ln]);
lastMatch:= colon + 1;
for i:= 0 to 2 do
begin
comma:= ln.IndexOf(',', lastMatch);
if comma = -1 then break;
ATuple[i]:= ln.Substring(lastMatch, comma - lastMatch).Trim;
lastMatch:= comma + 1;
end;
ATuple[i]:= ln.Substring(lastMatch).Trim;
result:= i + 1;
end;
function ReadValue: string;
var
ln: string;
colon, i, lastMatch, comma: Integer;
begin
ln:= Trim(ReadLn);
colon:= ln.IndexOf(':');
if colon = -1 then raise Exception.CreateFmt('Invalid line:%s',[ln]);
result:= ln.Substring(colon + 1).Trim;
end;
var
Page: TAtlasPage;
Region: TAtlasRegion;
Line, Direction: string;
Tuple: TupleStringArray;
i: Integer;
begin
EndOf:= False;
Page:= nil;
Region:= nil;
while not EndOf do
begin
Line:= Trim(ReadLn);
if Length(Line) > 0 then
begin
if Page = nil then
begin
Page:= TAtlasPage.Create;
Page.Name:= Line;
//
if ReadTuple(Tuple) = 2 then
begin
Page.Width := Tuple[0].ToInteger;
Page.Height:= Tuple[1].ToInteger;
ReadTuple(Tuple);
end;
Page.Format:= TPageFormat(GetEnumValue(TypeInfo(TPageFormat), 'pf'+Tuple[0]));
//
ReadTuple(Tupl