CentrED/UOLib/UGump.pas

234 lines
6.2 KiB
Plaintext

(*
* 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 UGump;
{$mode objfpc}{$H+}
interface
uses
Classes, Imaging, ImagingTypes, ImagingClasses, UMulBlock, UGenericIndex;
type
TGumpIndex = class(TGenericIndex)
protected
function GetWidth: SmallInt;
function GetHeight: SmallInt;
procedure SetWidth(AValue: SmallInt);
procedure SetHeight(AValue: SmallInt);
published
property Width: SmallInt read GetWidth write SetWidth;
property Height: SmallInt read GetHeight write SetHeight;
end;
TGump = class(TMulBlock)
constructor Create(AData: TStream; AIndex: TGumpIndex); overload;
constructor Create(AWidth, AHeight: Integer); overload;
destructor Destroy; override;
function Clone: TGump; override;
function GetSize: Integer; override;
procedure Write(AData: TStream); override;
procedure RefreshBuffer;
protected
FGraphic: TSingleImage;
FBuffer: TStream;
published
property Graphic: TSingleImage read FGraphic;
end;
implementation
type
PWordArray = ^TWordArray;
TWordArray = array[0..16383] of Word;
{ TGumpIndex }
function TGumpIndex.GetHeight: SmallInt;
var
sizeInfo: LongInt;
sizeInfoW: array[0..1] of SmallInt absolute sizeInfo;
begin
sizeInfo := FVarious;
Result := sizeInfoW[0];
end;
function TGumpIndex.GetWidth: SmallInt;
var
sizeInfo: LongInt;
sizeInfoW: array[0..1] of SmallInt absolute sizeInfo;
begin
sizeInfo := FVarious;
Result := sizeInfoW[1];
end;
procedure TGumpIndex.SetHeight(AValue: SmallInt);
var
sizeInfo: LongInt;
sizeInfoW: array[0..1] of SmallInt absolute sizeInfo;
begin
sizeInfo := FVarious;
sizeInfoW[0] := AValue;
FVarious := sizeInfo;
end;
procedure TGumpIndex.SetWidth(AValue: SmallInt);
var
sizeInfo: LongInt;
sizeInfoW: array[0..1] of SmallInt absolute sizeInfo;
begin
sizeInfo := FVarious;
sizeInfoW[1] := AValue;
FVarious := sizeInfo;
end;
{ TGump }
constructor TGump.Create(AData: TStream; AIndex: TGumpIndex);
var
iCurrentHeight, iCurrentWidth, i: Integer;
RowLookup: array of integer;
Offset: Integer;
Value, Run: Word;
block: TMemoryStream;
begin
inherited Create;
FGraphic := TSingleImage.CreateFromParams(AIndex.Width, AIndex.Height, ifA1R5G5B5);
FBuffer := TMemoryStream.Create;
SetLength(RowLookup, AIndex.Height);
if assigned(AData) then
begin
AData.Position := AIndex.Lookup;
block := TMemoryStream.Create;
block.CopyFrom(AData, AIndex.Size);
block.Position := 0;
for i := 0 to AIndex.Height - 1 do
begin
block.Read(Offset, SizeOf(Integer));
RowLookup[i] := Offset * 4;
end;
for iCurrentHeight := 0 to AIndex.Height - 1 do
begin
block.Position := RowLookup[iCurrentHeight];
iCurrentWidth := 0;
while iCurrentWidth < AIndex.Width do
begin
block.Read(Value, SizeOf(Word));
block.Read(Run, SizeOf(Word));
if Value > 0 then Value := Value or $8000; //Set alpha bit of non-black colors
for i := 0 to Run - 1 do
PWordArray(FGraphic.Bits + iCurrentHeight * AIndex.Width * 2)^[iCurrentWidth + i] := Value;
inc(iCurrentWidth, Run);
end;
end;
block.Free;
end;
FGraphic.Format := ifA8R8G8B8;
end;
constructor TGump.Create(AWidth, AHeight: Integer);
begin
{TODO : WARNING! Width and Height got switched since MulEditor!}
inherited Create;
FGraphic := TSingleImage.CreateFromParams(AWidth, AHeight, ifA8R8G8B8);
FBuffer := TMemoryStream.Create;
end;
destructor TGump.Destroy;
begin
if assigned(FGraphic) then FGraphic.Free;
if assigned(FBuffer) then FBuffer.Free;
inherited Destroy;
end;
function TGump.Clone: TGump;
begin
Result := TGump.Create(FGraphic.Width, FGraphic.Height);
Result.FGraphic.Assign(FGraphic);
end;
procedure TGump.Write(AData: TStream);
begin
FBuffer.Position := 0;
AData.CopyFrom(FBuffer, FBuffer.Size);
end;
function TGump.GetSize: Integer;
begin
RefreshBuffer;
Result := FBuffer.Size;
end;
procedure TGump.RefreshBuffer;
var
argbGraphic: TSingleImage;
colorBuffer: PWordArray;
runBuffer: array of Word;
offsetBuffer: array of Integer;
currentColor, currentRun: Integer;
iCurrentHeight, i: Integer;
begin
argbGraphic := TSingleImage.CreateFromImage(FGraphic);
argbGraphic.Format := ifA1R5G5B5;
SetLength(runBuffer, argbGraphic.Width);
SetLength(offsetBuffer, argbGraphic.Height);
FBuffer.Size := argbGraphic.Height * SizeOf(Integer);
FBuffer.Position := FBuffer.Size;
for iCurrentHeight := 0 to argbGraphic.Height - 1 do
begin
colorBuffer := argbGraphic.Bits + iCurrentHeight * argbGraphic.Width * 2;
for i := 0 to argbGraphic.Width - 1 do
begin
runBuffer[i] := 1;
colorBuffer^[i] := colorBuffer^[i] and not $8000; //eleminate alpha bit
end;
currentRun := 0;
currentColor := colorBuffer^[0];
for i := 1 to argbGraphic.Width - 1 do
begin
if colorBuffer^[i] = currentColor then
Inc(runBuffer[currentRun])
else
Inc(currentRun);
currentColor := colorBuffer^[i];
end;
offsetBuffer[iCurrentHeight] := FBuffer.Position div 4;
currentColor := 0;
for i := 0 to currentRun do
begin
FBuffer.Write(colorBuffer^[currentColor], SizeOf(Word));
FBuffer.Write(runBuffer[i], SizeOf(Word));
Inc(currentColor, runBuffer[i]);
end;
end;
FBuffer.Position := 0;
for i := 0 to argbGraphic.Height - 1 do FBuffer.Write(offsetBuffer[i], SizeOf(Integer));
argbGraphic.Free;
end;
end.