diff --git a/Client/CentrED.lpi b/Client/CentrED.lpi
index 534ff2c..35248ae 100644
--- a/Client/CentrED.lpi
+++ b/Client/CentrED.lpi
@@ -56,7 +56,7 @@
-
+
@@ -298,6 +298,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/CentrED.lpr b/Client/CentrED.lpr
index 56d24be..eccb8ac 100644
--- a/Client/CentrED.lpr
+++ b/Client/CentrED.lpr
@@ -42,7 +42,7 @@ uses
UGUIPlatformUtils, UPlatformTypes, UfrmRegionControl, UPackets,
UPacketHandlers, UAdminHandling, UGameResources, ULandscape, UfrmToolWindow,
Logging, UTileDataProvider, UMap, UWorldItem, UStatics, UTiledata, UAnimData,
- UGLFont, UAnimDataProvider, UMulManager;
+ UGLFont, UAnimDataProvider, UMulManager, UArtProvider, UTexmapProvider;
{$IFDEF WINDOWS}{$R CentrED.rc}{$ENDIF}
diff --git a/Client/UGameResources.pas b/Client/UGameResources.pas
index 7b6ab05..50c3cfd 100644
--- a/Client/UGameResources.pas
+++ b/Client/UGameResources.pas
@@ -37,7 +37,7 @@ type
{ TGameResourceManager }
- TGameResourceManager = class(TObject)
+ TGameResourceManager = class
constructor Create(ADataDir: string);
destructor Destroy; override;
protected
diff --git a/MulProvider/UArtProvider.pas b/MulProvider/UArtProvider.pas
index a92e04a..46e3353 100644
--- a/MulProvider/UArtProvider.pas
+++ b/MulProvider/UArtProvider.pas
@@ -1,97 +1,97 @@
-(*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * http://www.opensource.org/licenses/cddl1.php.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * http://www.opensource.org/licenses/cddl1.php. If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying * information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Portions Copyright 2007 Andreas Schneider
- *)
-unit UArtProvider;
-
-{$mode objfpc}{$H+}
-
-interface
-
-uses
- Graphics, UMulProvider, UMulBlock, UGenericIndex, UArt, UHue;
-
-type
- TArtProvider = class(TIndexedMulProvider)
- protected
- function GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock; override;
- function GetArtData(AID: Integer; AIndex: TGenericIndex; AColor: Word; AHue: THue; APartialHue: Boolean): TArt;
- public
- function GetArt(AID: Integer; AColor: Word; AHue: THue; APartialHue: Boolean): TArt;
- function GetFlatLand(AID: Integer): TArt;
- end;
-
-implementation
-
-{ TArtProvider }
-
-function TArtProvider.GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock;
-begin
- Result := GetArtData(AID, AIndex, clBlack, nil, False);
-end;
-
-function TArtProvider.GetArtData(AID: Integer; AIndex: TGenericIndex;
- AColor: Word; AHue: THue; APartialHue: Boolean): TArt;
-begin
- if AIndex.Lookup <> LongInt($FFFFFFFF) then
- begin
- if AID < $4000 then
- Result := TArt.Create(FData, AIndex, atLand, AColor, AHue, APartialHue)
- else
- Result := TArt.Create(FData, AIndex, atStatic, AColor, AHue, APartialHue);
- end else
- begin
- if AID < $4000 then
- Result := TArt.Create(nil, nil, atLand, AColor, AHue, APartialHue)
- else
- Result := TArt.Create(nil, nil, atStatic, AColor, AHue, APartialHue);
- end;
- Result.ID := AID;
-end;
-
-function TArtProvider.GetArt(AID: Integer; AColor: Word; AHue: THue; APartialHue: Boolean): TArt;
-var
- genericIndex: TGenericIndex;
-begin
- FIndex.Position := CalculateIndexOffset(AID);
- genericIndex := TGenericIndex.Create(FIndex);
- Result := GetArtData(AID, genericIndex, AColor, AHue, APartialHue);
- genericIndex.Free;
- Result.OnChanged := @OnChanged;
- Result.OnFinished := @OnFinished;
-end;
-
-function TArtProvider.GetFlatLand(AID: Integer): TArt;
-var
- genericIndex: TGenericIndex;
-begin
- FIndex.Position := CalculateIndexOffset(AID);
- genericIndex := TGenericIndex.Create(FIndex);
- Result := TArt.Create(FData, genericIndex, atLandFlat);
- genericIndex.Free;
- Result.OnChanged := @OnChanged;
- Result.OnFinished := @OnFinished;
-end;
-
-end.
+(*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * http://www.opensource.org/licenses/cddl1.php.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * http://www.opensource.org/licenses/cddl1.php. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2009 Andreas Schneider
+ *)
+unit UArtProvider;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Graphics, UMulProvider, UMulBlock, UGenericIndex, UArt, UHue;
+
+type
+ TArtProvider = class(TIndexedMulProvider)
+ protected
+ function GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock; override;
+ function GetArtData(AID: Integer; AIndex: TGenericIndex; AColor: Word; AHue: THue; APartialHue: Boolean): TArt;
+ public
+ function GetArt(AID: Integer; AColor: Word; AHue: THue; APartialHue: Boolean): TArt;
+ function GetFlatLand(AID: Integer): TArt;
+ end;
+
+implementation
+
+{ TArtProvider }
+
+function TArtProvider.GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock;
+begin
+ Result := GetArtData(AID, AIndex, clBlack, nil, False);
+end;
+
+function TArtProvider.GetArtData(AID: Integer; AIndex: TGenericIndex;
+ AColor: Word; AHue: THue; APartialHue: Boolean): TArt;
+begin
+ if (AIndex.Lookup > -1) and (AIndex.Size > 0) then
+ begin
+ if AID < $4000 then
+ Result := TArt.Create(FData, AIndex, atLand, AColor, AHue, APartialHue)
+ else
+ Result := TArt.Create(FData, AIndex, atStatic, AColor, AHue, APartialHue);
+ end else
+ begin
+ if AID < $4000 then
+ Result := TArt.Create(nil, nil, atLand, AColor, AHue, APartialHue)
+ else
+ Result := TArt.Create(nil, nil, atStatic, AColor, AHue, APartialHue);
+ end;
+ Result.ID := AID;
+end;
+
+function TArtProvider.GetArt(AID: Integer; AColor: Word; AHue: THue; APartialHue: Boolean): TArt;
+var
+ genericIndex: TGenericIndex;
+begin
+ FIndex.Position := CalculateIndexOffset(AID);
+ genericIndex := TGenericIndex.Create(FIndex);
+ Result := GetArtData(AID, genericIndex, AColor, AHue, APartialHue);
+ genericIndex.Free;
+ Result.OnChanged := @OnChanged;
+ Result.OnFinished := @OnFinished;
+end;
+
+function TArtProvider.GetFlatLand(AID: Integer): TArt;
+var
+ genericIndex: TGenericIndex;
+begin
+ FIndex.Position := CalculateIndexOffset(AID);
+ genericIndex := TGenericIndex.Create(FIndex);
+ Result := TArt.Create(FData, genericIndex, atLandFlat);
+ genericIndex.Free;
+ Result.OnChanged := @OnChanged;
+ Result.OnFinished := @OnFinished;
+end;
+
+end.
diff --git a/MulProvider/UMulProvider.pas b/MulProvider/UMulProvider.pas
index b266c4b..6b4df43 100644
--- a/MulProvider/UMulProvider.pas
+++ b/MulProvider/UMulProvider.pas
@@ -1,378 +1,387 @@
-(*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * http://www.opensource.org/licenses/cddl1.php.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * http://www.opensource.org/licenses/cddl1.php. If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying * information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Portions Copyright 2007 Andreas Schneider
- *)
-unit UMulProvider;
-
-{$mode objfpc}{$H+}
-
-interface
-
-uses
- SysUtils, Classes, UBufferedStreams, UMulBlock, UGenericIndex;
-
-type
- TOnProgressEvent = procedure(Total, Current: Integer) of object;
- TMulEventHandler = class(TObject)
- constructor Create;
- destructor Destroy; override;
- protected
- FEvents: TList;
- public
- procedure RegisterEvent(AEvent: TMulBlockChanged);
- procedure UnregisterEvent(AEvent: TMulBlockChanged);
- procedure FireEvents(ABlock: TMulBlock);
- end;
- TMulProvider = class(TObject)
- constructor Create; overload; virtual;
- constructor Create(AData: TStream; AReadOnly: Boolean = False); overload; virtual;
- constructor Create(AData: string; AReadOnly: Boolean = False); overload; virtual;
- destructor Destroy; override;
- protected
- FData: TStream;
- FOwnsData: Boolean;
- FReadOnly: Boolean;
- FChangeEvents: TMulEventHandler;
- FFinishedEvents: TMulEventHandler;
- function CalculateOffset(AID: Integer): Integer; virtual; abstract;
- function GetData(AID, AOffset: Integer): TMulBlock; virtual; abstract;
- procedure SetData(AID, AOffset: Integer; ABlock: TMulBlock); virtual;
- procedure OnChanged(ABlock: TMulBlock);
- procedure OnFinished(ABlock: TMulBlock);
- public
- function GetBlock(AID: Integer): TMulBlock; virtual;
- procedure SetBlock(AID: Integer; ABlock: TMulBlock); virtual;
- procedure RegisterOnChangeEvent(AEvent: TMulBlockChanged);
- procedure UnregisterOnChangeEvent(AEvent: TMulBlockChanged);
- procedure RegisterOnFinishedEvent(AEvent: TMulBlockChanged);
- procedure UnregisterOnFinishedEvent(AEvent: TMulBlockChanged);
- property Block[ID: Integer]: TMulBlock read GetBlock write SetBlock;
- property Data: TStream read FData;
- end;
- TIndexedMulProvider = class(TMulProvider)
- constructor Create(AData, AIndex: TStream; AReadOnly: Boolean = False); overload; virtual;
- constructor Create(AData, AIndex: string; AReadOnly: Boolean = False); overload; virtual;
- destructor Destroy; override;
- protected
- FIndex: TBufferedReader;
- function CalculateIndexOffset(AID: Integer): Integer; virtual;
- function GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock; reintroduce; virtual; abstract;
- procedure SetData(AID: Integer; AIndex: TGenericIndex; ABlock: TMulBlock); reintroduce; virtual;
- function GetVarious(AID: Integer; ABlock: TMulBlock; ADefault: Integer): Integer; virtual;
- public
- function GetBlock(AID: Integer): TMulBlock; override;
- procedure GetBlockEx(AID: Integer; var ABlock: TMulBlock; var AIndex: TGenericIndex); virtual;
- procedure SetBlock(AID: Integer; ABlock: TMulBlock); override;
- function Exists(AID: Integer): Boolean; virtual;
- procedure Defragment(ATempStream: TStream; AOnProgress: TOnProgressEvent = nil); virtual;
- property Index: TBufferedReader read FIndex;
- end;
-
-implementation
-
-type
- PMethod = ^TMethod;
-
-{ TMulEventHandler }
-
-constructor TMulEventHandler.Create;
-begin
- inherited;
- FEvents := TList.Create;
-end;
-
-destructor TMulEventHandler.Destroy;
-var
- i: Integer;
-begin
- if Assigned(FEvents) then
- begin
- for i := 0 to FEvents.Count - 1 do
- Dispose(PMethod(FEvents.Items[i]));
- FreeAndNil(FEvents);
- end;
- inherited;
-end;
-
-procedure TMulEventHandler.FireEvents(ABlock: TMulBlock);
-var
- i: Integer;
-begin
- for i := 0 to FEvents.Count - 1 do
- TMulBlockChanged(FEvents.Items[i]^)(ABlock);
-end;
-
-procedure TMulEventHandler.RegisterEvent(AEvent: TMulBlockChanged);
-var
- eventInfo: PMethod;
-begin
- UnregisterEvent(AEvent);
- New(eventInfo);
- eventInfo^.Code := TMethod(AEvent).Code;
- eventInfo^.Data := TMethod(AEvent).Data;
- FEvents.Add(eventInfo);
-end;
-
-procedure TMulEventHandler.UnregisterEvent(AEvent: TMulBlockChanged);
-var
- i: Integer;
-
- function RemoveEntry: Boolean;
- begin
- Dispose(PMethod(FEvents.Items[i]));
- FEvents.Delete(i);
- Result := True;
- end;
-
-begin
- i := 0;
- while (i < FEvents.Count) and ((TMethod(AEvent).Code <> TMethod(FEvents.Items[i]^).Code) or (TMethod(AEvent).Data <> TMethod(FEvents.Items[i]^).Data) or not RemoveEntry) do
- Inc(i);
-end;
-
-{ TMulProvider }
-
-constructor TMulProvider.Create(AData: TStream; AReadOnly: Boolean = False);
-begin
- Create;
- FData := AData;
- FOwnsData := False;
- FReadOnly := AReadOnly;
-end;
-
-constructor TMulProvider.Create(AData: string; AReadOnly: Boolean = False);
-var
- mode: Word;
-begin
- Create;
- if AReadOnly then
- mode := fmOpenRead or fmShareDenyWrite
- else
- mode := fmOpenReadWrite or fmShareDenyWrite;
- FData := TFileStream.Create(AData, mode);
- FOwnsData := True;
- FReadOnly := AReadOnly;
-end;
-
-constructor TMulProvider.Create;
-begin
- inherited;
- FChangeEvents := TMulEventHandler.Create;
- FFinishedEvents := TMulEventHandler.Create;
-end;
-
-destructor TMulProvider.Destroy;
-begin
- if FOwnsData and Assigned(FData) then FreeAndNil(FData);
- if Assigned(FChangeEvents) then FreeAndNil(FChangeEvents);
- if Assigned(FFinishedEvents) then FreeAndNil(FFinishedEvents);
- inherited;
-end;
-
-function TMulProvider.GetBlock(AID: Integer): TMulBlock;
-begin
- Result := GetData(AID, CalculateOffset(AID));
- Result.OnChanged := @OnChanged;
- Result.OnFinished := @OnFinished;
-end;
-
-procedure TMulProvider.OnChanged(ABlock: TMulBlock);
-begin
- SetBlock(ABlock.ID, ABlock);
- FChangeEvents.FireEvents(ABlock);
-end;
-
-procedure TMulProvider.OnFinished(ABlock: TMulBlock);
-begin
- FFinishedEvents.FireEvents(ABlock);
- ABlock.Free;
-end;
-
-procedure TMulProvider.RegisterOnChangeEvent(AEvent: TMulBlockChanged);
-begin
- FChangeEvents.RegisterEvent(AEvent);
-end;
-
-procedure TMulProvider.RegisterOnFinishedEvent(AEvent: TMulBlockChanged);
-begin
- FFinishedEvents.RegisterEvent(AEvent);
-end;
-
-procedure TMulProvider.SetBlock(AID: Integer; ABlock: TMulBlock);
-begin
- if FReadOnly then Exit;
- SetData(AID, CalculateOffset(AID), ABlock);
-end;
-
-procedure TMulProvider.SetData(AID, AOffset: Integer; ABlock: TMulBlock);
-begin
- if FReadOnly then Exit;
- FData.Position := AOffset;
- ABlock.Write(FData);
-end;
-
-procedure TMulProvider.UnregisterOnChangeEvent(AEvent: TMulBlockChanged);
-begin
- FChangeEvents.UnregisterEvent(AEvent);
-end;
-
-procedure TMulProvider.UnregisterOnFinishedEvent(AEvent: TMulBlockChanged);
-begin
- FFinishedEvents.UnregisterEvent(AEvent);
-end;
-
-{ TIndexedMulProvider }
-
-function TIndexedMulProvider.CalculateIndexOffset(AID: Integer): Integer;
-begin
- Result := 12 * AID;
-end;
-
-constructor TIndexedMulProvider.Create(AData, AIndex: TStream; AReadOnly: Boolean = False);
-begin
- inherited Create(AData, AReadOnly);
- FIndex := TBufferedReader.Create(AIndex);
-end;
-
-constructor TIndexedMulProvider.Create(AData, AIndex: string; AReadOnly: Boolean = False);
-var
- mode: Word;
-begin
- inherited Create(AData, AReadOnly);
- if AReadOnly then
- mode := fmOpenRead or fmShareDenyWrite
- else
- mode := fmOpenReadWrite or fmShareDenyWrite;
- FIndex := TBufferedReader.Create(TFileStream.Create(AIndex, mode), True);
-end;
-
-procedure TIndexedMulProvider.Defragment(ATempStream: TStream; AOnProgress: TOnProgressEvent = nil);
-var
- genericIndex: TGenericIndex;
-begin
- if FReadOnly then Exit;
- ATempStream.Size := FData.Size;
- ATempStream.Position := 0;
- FIndex.Position := 0;
- while FIndex.Position < FIndex.Size do
- begin
- genericIndex := TGenericIndex.Create(FIndex);
- if genericIndex.Lookup <> LongInt($FFFFFFFF) then
- begin
- FData.Position := genericIndex.Lookup;
- genericIndex.Lookup := ATempStream.Position;
- ATempStream.CopyFrom(FData, genericIndex.Size);
- FIndex.Seek(-12, soFromCurrent);
- genericIndex.Write(FIndex);
- end;
- genericIndex.Free;
- if Assigned(AOnProgress) and (FIndex.Position mod 1200 = 0) then
- AOnProgress(FIndex.Size, FIndex.Position);
- end;
- FData.Size := ATempStream.Position;
- FData.Position := 0;
- ATempStream.Position := 0;
- FData.CopyFrom(ATempStream, FData.Size);
-end;
-
-destructor TIndexedMulProvider.Destroy;
-begin
- if Assigned(FIndex) then FreeAndNil(FIndex);
- inherited;
-end;
-
-function TIndexedMulProvider.Exists(AID: Integer): Boolean;
-var
- genericIndex: TGenericIndex;
-begin
- FIndex.Position := CalculateIndexOffset(AID);
- genericIndex := TGenericIndex.Create(FIndex);
- Result := genericIndex.Lookup <> LongInt($FFFFFFFF);
- genericIndex.Free;
-end;
-
-function TIndexedMulProvider.GetBlock(AID: Integer): TMulBlock;
-var
- genericIndex: TGenericIndex;
-begin
- GetBlockEx(AID, Result, genericIndex);
- genericIndex.Free;
-end;
-
-procedure TIndexedMulProvider.GetBlockEx(AID: Integer;
- var ABlock: TMulBlock; var AIndex: TGenericIndex);
-begin
- FIndex.Position := CalculateIndexOffset(AID);
- AIndex := TGenericIndex.Create(FIndex);
- ABlock := GetData(AID, AIndex);
- ABlock.OnChanged := @OnChanged;
- ABlock.OnFinished := @OnFinished;
-end;
-
-function TIndexedMulProvider.GetVarious(AID: Integer; ABlock: TMulBlock;
- ADefault: Integer): Integer;
-begin
- Result := ADefault;
-end;
-
-procedure TIndexedMulProvider.SetBlock(AID: Integer; ABlock: TMulBlock);
-var
- genericIndex: TGenericIndex;
-begin
- if FReadOnly then Exit;
- FIndex.Position := CalculateIndexOffset(AID);
- genericIndex := TGenericIndex.Create(FIndex);
- SetData(AID, genericIndex, ABlock);
- FIndex.Position := CalculateIndexOffset(AID);
- genericIndex.Various := GetVarious(AID, ABlock, genericIndex.Various);
- genericIndex.Write(FIndex);
- genericIndex.Free;
-end;
-
-procedure TIndexedMulProvider.SetData(AID: Integer; AIndex: TGenericIndex;
- ABlock: TMulBlock);
-var
- size: Integer;
-begin
- if FReadOnly then Exit;
- size := ABlock.GetSize;
- if size = 0 then
- begin
- AIndex.Lookup := LongInt($FFFFFFFF);
- AIndex.Various := LongInt($FFFFFFFF);
- end else if (size > AIndex.Size) or (AIndex.Lookup = LongInt($FFFFFFFF)) then
- begin
- FData.Position := FData.Size;
- AIndex.Lookup := FData.Position;
- ABlock.Write(FData);
- end else
- begin
- FData.Position := AIndex.Lookup;
- ABlock.Write(FData);
- end;
- AIndex.Size := size;
-end;
-
-end.
-
+(*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * http://www.opensource.org/licenses/cddl1.php.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * http://www.opensource.org/licenses/cddl1.php. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2009 Andreas Schneider
+ *)
+unit UMulProvider;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ SysUtils, Classes, UBufferedStreams, UMulBlock, UGenericIndex;
+
+type
+ TOnProgressEvent = procedure(Total, Current: Integer) of object;
+
+ { TMulEventHandler }
+
+ TMulEventHandler = class
+ constructor Create;
+ destructor Destroy; override;
+ protected
+ FEvents: TList;
+ public
+ procedure RegisterEvent(AEvent: TMulBlockChanged);
+ procedure UnregisterEvent(AEvent: TMulBlockChanged);
+ procedure FireEvents(ABlock: TMulBlock);
+ end;
+
+ { TMulProvider }
+
+ TMulProvider = class
+ constructor Create; overload; virtual;
+ constructor Create(AData: TStream; AReadOnly: Boolean = False); overload; virtual;
+ constructor Create(AData: string; AReadOnly: Boolean = False); overload; virtual;
+ destructor Destroy; override;
+ protected
+ FData: TStream;
+ FOwnsData: Boolean;
+ FReadOnly: Boolean;
+ FChangeEvents: TMulEventHandler;
+ FFinishedEvents: TMulEventHandler;
+ function CalculateOffset(AID: Integer): Integer; virtual; abstract;
+ function GetData(AID, AOffset: Integer): TMulBlock; virtual; abstract;
+ procedure SetData(AID, AOffset: Integer; ABlock: TMulBlock); virtual;
+ procedure OnChanged(ABlock: TMulBlock);
+ procedure OnFinished(ABlock: TMulBlock);
+ public
+ function GetBlock(AID: Integer): TMulBlock; virtual;
+ procedure SetBlock(AID: Integer; ABlock: TMulBlock); virtual;
+ procedure RegisterOnChangeEvent(AEvent: TMulBlockChanged);
+ procedure UnregisterOnChangeEvent(AEvent: TMulBlockChanged);
+ procedure RegisterOnFinishedEvent(AEvent: TMulBlockChanged);
+ procedure UnregisterOnFinishedEvent(AEvent: TMulBlockChanged);
+ property Block[ID: Integer]: TMulBlock read GetBlock write SetBlock;
+ property Data: TStream read FData;
+ end;
+
+ { TIndexedMulProvider }
+
+ TIndexedMulProvider = class(TMulProvider)
+ constructor Create(AData, AIndex: TStream; AReadOnly: Boolean = False); overload; virtual;
+ constructor Create(AData, AIndex: string; AReadOnly: Boolean = False); overload; virtual;
+ destructor Destroy; override;
+ protected
+ FIndex: TBufferedReader;
+ function CalculateIndexOffset(AID: Integer): Integer; virtual;
+ function GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock; reintroduce; virtual; abstract;
+ procedure SetData(AID: Integer; AIndex: TGenericIndex; ABlock: TMulBlock); reintroduce; virtual;
+ function GetVarious(AID: Integer; ABlock: TMulBlock; ADefault: Integer): Integer; virtual;
+ public
+ function GetBlock(AID: Integer): TMulBlock; override;
+ procedure GetBlockEx(AID: Integer; var ABlock: TMulBlock; var AIndex: TGenericIndex); virtual;
+ procedure SetBlock(AID: Integer; ABlock: TMulBlock); override;
+ function Exists(AID: Integer): Boolean; virtual;
+ procedure Defragment(ATempStream: TStream; AOnProgress: TOnProgressEvent = nil); virtual;
+ property Index: TBufferedReader read FIndex;
+ end;
+
+implementation
+
+type
+ PMethod = ^TMethod;
+
+{ TMulEventHandler }
+
+constructor TMulEventHandler.Create;
+begin
+ inherited;
+ FEvents := TList.Create;
+end;
+
+destructor TMulEventHandler.Destroy;
+var
+ i: Integer;
+begin
+ if Assigned(FEvents) then
+ begin
+ for i := 0 to FEvents.Count - 1 do
+ Dispose(PMethod(FEvents.Items[i]));
+ FreeAndNil(FEvents);
+ end;
+ inherited;
+end;
+
+procedure TMulEventHandler.FireEvents(ABlock: TMulBlock);
+var
+ i: Integer;
+begin
+ for i := 0 to FEvents.Count - 1 do
+ TMulBlockChanged(FEvents.Items[i]^)(ABlock);
+end;
+
+procedure TMulEventHandler.RegisterEvent(AEvent: TMulBlockChanged);
+var
+ eventInfo: PMethod;
+begin
+ UnregisterEvent(AEvent);
+ New(eventInfo);
+ eventInfo^.Code := TMethod(AEvent).Code;
+ eventInfo^.Data := TMethod(AEvent).Data;
+ FEvents.Add(eventInfo);
+end;
+
+procedure TMulEventHandler.UnregisterEvent(AEvent: TMulBlockChanged);
+var
+ i: Integer;
+
+ function RemoveEntry: Boolean;
+ begin
+ Dispose(PMethod(FEvents.Items[i]));
+ FEvents.Delete(i);
+ Result := True;
+ end;
+
+begin
+ i := 0;
+ while (i < FEvents.Count) and ((TMethod(AEvent).Code <> TMethod(FEvents.Items[i]^).Code) or (TMethod(AEvent).Data <> TMethod(FEvents.Items[i]^).Data) or not RemoveEntry) do
+ Inc(i);
+end;
+
+{ TMulProvider }
+
+constructor TMulProvider.Create(AData: TStream; AReadOnly: Boolean = False);
+begin
+ Create;
+ FData := AData;
+ FOwnsData := False;
+ FReadOnly := AReadOnly;
+end;
+
+constructor TMulProvider.Create(AData: string; AReadOnly: Boolean = False);
+var
+ mode: Word;
+begin
+ Create;
+ if AReadOnly then
+ mode := fmOpenRead or fmShareDenyWrite
+ else
+ mode := fmOpenReadWrite or fmShareDenyWrite;
+ FData := TFileStream.Create(AData, mode);
+ FOwnsData := True;
+ FReadOnly := AReadOnly;
+end;
+
+constructor TMulProvider.Create;
+begin
+ inherited;
+ FChangeEvents := TMulEventHandler.Create;
+ FFinishedEvents := TMulEventHandler.Create;
+end;
+
+destructor TMulProvider.Destroy;
+begin
+ if FOwnsData and Assigned(FData) then FreeAndNil(FData);
+ if Assigned(FChangeEvents) then FreeAndNil(FChangeEvents);
+ if Assigned(FFinishedEvents) then FreeAndNil(FFinishedEvents);
+ inherited;
+end;
+
+function TMulProvider.GetBlock(AID: Integer): TMulBlock;
+begin
+ Result := GetData(AID, CalculateOffset(AID));
+ Result.OnChanged := @OnChanged;
+ Result.OnFinished := @OnFinished;
+end;
+
+procedure TMulProvider.OnChanged(ABlock: TMulBlock);
+begin
+ SetBlock(ABlock.ID, ABlock);
+ FChangeEvents.FireEvents(ABlock);
+end;
+
+procedure TMulProvider.OnFinished(ABlock: TMulBlock);
+begin
+ FFinishedEvents.FireEvents(ABlock);
+ ABlock.Free;
+end;
+
+procedure TMulProvider.RegisterOnChangeEvent(AEvent: TMulBlockChanged);
+begin
+ FChangeEvents.RegisterEvent(AEvent);
+end;
+
+procedure TMulProvider.RegisterOnFinishedEvent(AEvent: TMulBlockChanged);
+begin
+ FFinishedEvents.RegisterEvent(AEvent);
+end;
+
+procedure TMulProvider.SetBlock(AID: Integer; ABlock: TMulBlock);
+begin
+ if FReadOnly then Exit;
+ SetData(AID, CalculateOffset(AID), ABlock);
+end;
+
+procedure TMulProvider.SetData(AID, AOffset: Integer; ABlock: TMulBlock);
+begin
+ if FReadOnly then Exit;
+ FData.Position := AOffset;
+ ABlock.Write(FData);
+end;
+
+procedure TMulProvider.UnregisterOnChangeEvent(AEvent: TMulBlockChanged);
+begin
+ FChangeEvents.UnregisterEvent(AEvent);
+end;
+
+procedure TMulProvider.UnregisterOnFinishedEvent(AEvent: TMulBlockChanged);
+begin
+ FFinishedEvents.UnregisterEvent(AEvent);
+end;
+
+{ TIndexedMulProvider }
+
+function TIndexedMulProvider.CalculateIndexOffset(AID: Integer): Integer;
+begin
+ Result := 12 * AID;
+end;
+
+constructor TIndexedMulProvider.Create(AData, AIndex: TStream; AReadOnly: Boolean = False);
+begin
+ inherited Create(AData, AReadOnly);
+ FIndex := TBufferedReader.Create(AIndex);
+end;
+
+constructor TIndexedMulProvider.Create(AData, AIndex: string; AReadOnly: Boolean = False);
+var
+ mode: Word;
+begin
+ inherited Create(AData, AReadOnly);
+ if AReadOnly then
+ mode := fmOpenRead or fmShareDenyWrite
+ else
+ mode := fmOpenReadWrite or fmShareDenyWrite;
+ FIndex := TBufferedReader.Create(TFileStream.Create(AIndex, mode), True);
+end;
+
+procedure TIndexedMulProvider.Defragment(ATempStream: TStream; AOnProgress: TOnProgressEvent = nil);
+var
+ genericIndex: TGenericIndex;
+begin
+ if FReadOnly then Exit;
+ ATempStream.Size := FData.Size;
+ ATempStream.Position := 0;
+ FIndex.Position := 0;
+ while FIndex.Position < FIndex.Size do
+ begin
+ genericIndex := TGenericIndex.Create(FIndex);
+ if genericIndex.Lookup <> LongInt($FFFFFFFF) then
+ begin
+ FData.Position := genericIndex.Lookup;
+ genericIndex.Lookup := ATempStream.Position;
+ ATempStream.CopyFrom(FData, genericIndex.Size);
+ FIndex.Seek(-12, soFromCurrent);
+ genericIndex.Write(FIndex);
+ end;
+ genericIndex.Free;
+ if Assigned(AOnProgress) and (FIndex.Position mod 1200 = 0) then
+ AOnProgress(FIndex.Size, FIndex.Position);
+ end;
+ FData.Size := ATempStream.Position;
+ FData.Position := 0;
+ ATempStream.Position := 0;
+ FData.CopyFrom(ATempStream, FData.Size);
+end;
+
+destructor TIndexedMulProvider.Destroy;
+begin
+ if Assigned(FIndex) then FreeAndNil(FIndex);
+ inherited;
+end;
+
+function TIndexedMulProvider.Exists(AID: Integer): Boolean;
+var
+ genericIndex: TGenericIndex;
+begin
+ FIndex.Position := CalculateIndexOffset(AID);
+ genericIndex := TGenericIndex.Create(FIndex);
+ Result := (genericIndex.Lookup > -1) and (genericIndex.Size > 0);
+ genericIndex.Free;
+end;
+
+function TIndexedMulProvider.GetBlock(AID: Integer): TMulBlock;
+var
+ genericIndex: TGenericIndex;
+begin
+ GetBlockEx(AID, Result, genericIndex);
+ genericIndex.Free;
+end;
+
+procedure TIndexedMulProvider.GetBlockEx(AID: Integer;
+ var ABlock: TMulBlock; var AIndex: TGenericIndex);
+begin
+ FIndex.Position := CalculateIndexOffset(AID);
+ AIndex := TGenericIndex.Create(FIndex);
+ ABlock := GetData(AID, AIndex);
+ ABlock.OnChanged := @OnChanged;
+ ABlock.OnFinished := @OnFinished;
+end;
+
+function TIndexedMulProvider.GetVarious(AID: Integer; ABlock: TMulBlock;
+ ADefault: Integer): Integer;
+begin
+ Result := ADefault;
+end;
+
+procedure TIndexedMulProvider.SetBlock(AID: Integer; ABlock: TMulBlock);
+var
+ genericIndex: TGenericIndex;
+begin
+ if FReadOnly then Exit;
+ FIndex.Position := CalculateIndexOffset(AID);
+ genericIndex := TGenericIndex.Create(FIndex);
+ SetData(AID, genericIndex, ABlock);
+ FIndex.Position := CalculateIndexOffset(AID);
+ genericIndex.Various := GetVarious(AID, ABlock, genericIndex.Various);
+ genericIndex.Write(FIndex);
+ genericIndex.Free;
+end;
+
+procedure TIndexedMulProvider.SetData(AID: Integer; AIndex: TGenericIndex;
+ ABlock: TMulBlock);
+var
+ size: Integer;
+begin
+ if FReadOnly then Exit;
+ size := ABlock.GetSize;
+ if size = 0 then
+ begin
+ AIndex.Lookup := LongInt($FFFFFFFF);
+ AIndex.Various := LongInt($FFFFFFFF);
+ end else if (size > AIndex.Size) or (AIndex.Lookup = LongInt($FFFFFFFF)) then
+ begin
+ FData.Position := FData.Size;
+ AIndex.Lookup := FData.Position;
+ ABlock.Write(FData);
+ end else
+ begin
+ FData.Position := AIndex.Lookup;
+ ABlock.Write(FData);
+ end;
+ AIndex.Size := size;
+end;
+
+end.
+
diff --git a/MulProvider/UTexmapProvider.pas b/MulProvider/UTexmapProvider.pas
index af891ba..b9fbd21 100644
--- a/MulProvider/UTexmapProvider.pas
+++ b/MulProvider/UTexmapProvider.pas
@@ -1,56 +1,56 @@
-(*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * http://www.opensource.org/licenses/cddl1.php.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * http://www.opensource.org/licenses/cddl1.php. If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying * information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Portions Copyright 2007 Andreas Schneider
- *)
-unit UTexmapProvider;
-
-{$mode objfpc}{$H+}
-
-interface
-
-uses
- UMulProvider, UMulBlock, UGenericIndex, UTexture;
-
-type
- TTexmapProvider = class(TIndexedMulProvider)
- protected
- function GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock; override;
- end;
-
-implementation
-
-{ TTexmapProvider }
-
-function TTexmapProvider.GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock;
-begin
- if AIndex.Lookup <> LongInt($FFFFFFFF) then
- Result := TTexture.Create(FData, AIndex)
- else
- Result := TTexture.Create(-1);
- Result.ID := AID;
-end;
-
-end.
-
-
+(*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * http://www.opensource.org/licenses/cddl1.php.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * http://www.opensource.org/licenses/cddl1.php. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2009 Andreas Schneider
+ *)
+unit UTexmapProvider;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ UMulProvider, UMulBlock, UGenericIndex, UTexture;
+
+type
+ TTexmapProvider = class(TIndexedMulProvider)
+ protected
+ function GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock; override;
+ end;
+
+implementation
+
+{ TTexmapProvider }
+
+function TTexmapProvider.GetData(AID: Integer; AIndex: TGenericIndex): TMulBlock;
+begin
+ if (AIndex.Lookup > -1) and (AIndex.Size > 0) then
+ Result := TTexture.Create(FData, AIndex)
+ else
+ Result := TTexture.Create(-1);
+ Result.ID := AID;
+end;
+
+end.
+
+