2010-07-25 00:18:54 +02:00
|
|
|
(*
|
|
|
|
* 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.
|
|
|
|
|