⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mirwil.pas

📁 很多人想要研究的真彩传奇2客户端,一般来说传奇2的客户端是256色的,现在出了个飞尔真彩传奇,想必很吸引大家的眼球.现在把我收藏的拿出来一起共享
💻 PAS
字号:
unit MirWil;

interface

uses
  SysUtils, Windows, Graphics, DirectDraw, Assist, ObjFastBlt;

{------------------------------------------------------------------------------}
// WIL 常量定义
{------------------------------------------------------------------------------}
var
  UseDIBSurface: Boolean = True; // 是否在创建 WIL Surface 时使用 DIB 绘制
                                  // 如果直接使用 WIL 文件中的位图 Bits 会出现少量颜色
                                  // 显示不正确,在传奇源代码中的结果也是如此。

{------------------------------------------------------------------------------}
// WIL 文件格式定义
{------------------------------------------------------------------------------}
type
  // WIL 文件头格式 (56Byte)
  PImageHeader = ^TImageHeader;
  TImageHeader = record
    Title: string[40]; // 库文件标题 'WEMADE Entertainment inc.'
    ImageCount: Integer; // 图片数量
    ColorCount: Integer; // 色彩数量
    PaletteSize: Integer; // 调色板大小
  end;

  // WIL 图像信息 (注意, 没有 pack record)
  PImageInfo = ^TImageInfo;
  TImageInfo = record
    Width: SmallInt; // 位图宽度
    Height: SmallInt; // 位图高度
    PX: SmallInt; // 未知,似乎不用也可
    PY: SmallInt; // 未知,似乎不用也可
    Bits: PByte; // 未使用, 实际从文件读出时,要少读 4 字节, 即是此值未读
  end;

  // WIX 索引文件头格式
  PIndexHeader = ^TIndexHeader;
  TIndexHeader = record
    Title: string[40]; // 'WEMADE Entertainment inc.'
    IndexCount: Integer; // 索引总数
  end;
  TRGBQuads = array[0..255] of TRGBQuad;
  PRGBQuads = ^TRGBQuads;
{------------------------------------------------------------------------------}
// TWilFile class
{------------------------------------------------------------------------------}

  // TWilFile
  TWilFile = class(TObject)
  private
    FFileName: string; // WIL 文件名
    FFileHandle: THandle; // 文件句柄
    FFileMapping: THandle; // 文件映射句柄
    FFilePointer: Pointer; // 文件内容指针(使用文件映射)

    FIndexArr: array of Integer; // 图片索引数组(从 WIX 文件中读取)
    FMainColorTable: PRGBQuads; // 调色板指针(直接指向 WIL 文件中)
    FImageCount: Integer; // 图片数量

    FSurfaces: array of TDxFastBlt;

    procedure LoadIndexFile; // 读入 WIX 文件至 IndexArr 中
    procedure CreateMapView; // 创建 WIL 文件映射
    function GetSurfaces(AIndex: Integer): TDxFastBlt;
    function GetImageInfo(AIndex: Integer): PImageInfo;
  public
    constructor Create(const AFileName: string);
    destructor Destroy; override;

    procedure SaveToFile(Index: Integer; const FileName: string);

    // 已打开的 WIL 文件名
    property FileName: string read FFileName;
    // 主调色板指针
    property MainColorTable: PRGBQuads read FMainColorTable;

    property ImageCount: Integer read FImageCount;
    // 图片的 Surface
    property Surfaces[AIndex: Integer]: TDxFastBlt read GetSurfaces;
    // 图片的信息
    property ImageInfo[AIndex: Integer]: PImageInfo read GetImageInfo;
  end;


implementation

{ TWilFile }

constructor TWilFile.Create(const AFileName: string);
begin
  FFileName := AFileName;

  // 读入图片索引文件
  LoadIndexFile;

  // 创建 WIL 文件的映射
  CreateMapView;

  // 读入 WIL 文件头数据

  // 读入文件头中的图片数量, (图片数量已由 LoadIndexFile 设置, 这是由
  // 于 Weapon.wix 中的数量错误导致的修改, savetime 2005.1.3)
  // FImageCount := PImageHeader(FFilePointer)^.ImageCount;

  // 设置 FSurfaces 数组大小
  SetLength(FSurfaces, FImageCount);
  // 保存调色板指针
  FMainColorTable := IncPointer(FFilePointer, SizeOf(TImageHeader));
end;

procedure TWilFile.CreateMapView;
var
  ContentFileName: string;
begin
  // WIL 文件名
  ContentFileName := FFileName + '.WIL';

  // 打开 WIL 文件
  FFileHandle := CreateFile(PChar(ContentFileName), GENERIC_READ, FILE_SHARE_READ, nil,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_RANDOM_ACCESS, 0);

  if FFileHandle = INVALID_HANDLE_VALUE then
    raise Exception.CreateFmt('打开文件 "%s" 失败!', [ContentFileName]);

  // 创建文件映射对象
  FFileMapping := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil);

  if FFileMapping = 0 then
  begin
    CloseHandle(FFileHandle);
    raise Exception.CreateFmt('创建文件映射 "%s" 失败!', [ContentFileName]);
  end;

  // 映射文件至内存
  FFilePointer := MapViewOfFile(FFileMapping, FILE_MAP_READ, 0, 0, 0);
  if FFilePointer = nil then
  begin
    CloseHandle(FFileMapping);
    CloseHandle(FFileHandle);
    raise Exception.CreateFmt('映射文件 "%s" 失败!', [ContentFileName]);
  end;
end;

destructor TWilFile.Destroy;
var
  I: Integer;
begin
  // 清除索引文件内容
  SetLength(FIndexArr, 0);

  // 清除 FSurfaces 数组
  for I := 0 to Length(FSurfaces) - 1 do begin
    if FSurfaces[I] <> nil then begin
      FSurfaces[I].Free;
      FSurfaces[I] := nil;
    end;
  end;
  SetLength(FSurfaces, 0);

  // 关闭文件映射及相关句柄
  UnmapViewOfFile(FFilePointer);
  CloseHandle(FFileMapping);
  CloseHandle(FFileHandle);

  inherited;
end;

procedure TWilFile.LoadIndexFile;
var
  F: file;
  IdxHeader: TIndexHeader;
  NumRead: Integer;
  IndexFileName: string;
begin
  // 索引文件名
  IndexFileName := FFileName + '.WIX';

  // 打开索引文件
  FileMode := fmOpenRead;
  AssignFile(F, IndexFileName);
  Reset(F, 1);
  try
    // 读索引文件头
    BlockRead(F, IdxHeader, SizeOf(IdxHeader), NumRead);
    if NumRead <> SizeOf(IdxHeader) then
      raise Exception.CreateFmt('"%s" 文件头错误!', [IndexFileName]);

    // 设置索引数组大小
    SetLength(FIndexArr, IdxHeader.IndexCount);

    // 读索引内存至数组
    BlockRead(F, PInteger(FIndexArr)^, IdxHeader.IndexCount * 4, NumRead);
    if NumRead = IdxHeader.IndexCount * 4 then
      FImageCount := IdxHeader.IndexCount
    else
      // 由于 Weapon.wix 的索引文件头中的图片数与实际的索引个数不同, 为了兼容,
      // 即不触发异常, 详细情况见此文件最上标注.
      // raise Exception.CreateFmt('"%s" 文件内容错误!', [IndexFileName]);
      FImageCount := NumRead div 4;
  finally
    CloseFile(F);
  end;
end;

function TWilFile.GetSurfaces(AIndex: Integer): TDxFastBlt;
var
  InfoPtr: PImageInfo; // 图像信息, 使用临时变量将加快速度
  X, Y: Integer; // Surface 的行值
  PBits: PByte; // 指向 Bits 的指针
  cr, cg, cb: Byte;
  PDBits: PByte;
  Src: PByte;
begin
  // 检查 AIndex 是否合法
  if (AIndex < 0) or (AIndex >= FImageCount) then
    raise Exception.Create('TWilFile.GetSurfaces 数组超界!');

  // 如果索引位置的 FSurface 已经创建, 则直接返回该值
  Result := FSurfaces[AIndex];
  if FSurfaces[AIndex] <> nil then Exit;

  // 否则创建新的 FSurface[AIndex]
  InfoPtr := ImageInfo[AIndex];
  FSurfaces[AIndex] := TDxFastBlt.Create;
  FSurfaces[AIndex].Width := InfoPtr^.Width;
  FSurfaces[AIndex].Height := InfoPtr^.Height;
  FSurfaces[AIndex].PX := InfoPtr^.PX;
  FSurfaces[AIndex].PY := InfoPtr^.PY;

  PBits := IncPointer(InfoPtr, (SizeOf(TImageInfo) - 4) +
    ((InfoPtr^.Height - 1) * InfoPtr^.Width));

  //8Bit转32Bit
  for Y := 0 to InfoPtr^.Height - 1 do begin
    PDBits := Pointer(Integer(FSurfaces[AIndex].PBits) + FSurfaces[AIndex].Pitch * Y);
    Src := PBits;
    for X := 0 to InfoPtr^.Width - 1 do begin
      with FMainColorTable[PByte(Src)^] do begin
        cr := rgbRed;
        cg := rgbGreen;
        cb := rgbBlue;
      end;
      PInteger(PDBits)^ := ((cr shl 16) and $FF0000) or ((cg shl 8) and $00FF00) or ((cb shr 0) and $0000FF);
      Inc(PInteger(PDBits));
      Inc(PByte(Src));
    end;
    Dec(PBits, InfoPtr^.Width);
  end;
  FSurfaces[AIndex].TransparentColor := clBlack;
  Result := FSurfaces[AIndex];
end;

function TWilFile.GetImageInfo(AIndex: Integer): PImageInfo;
begin
  // 检查 AIndex 是否合法
  if (AIndex < 0) or (AIndex >= FImageCount) then
    raise Exception.Create('TWilFile.GetImageInfo 数组超界!');

  // 定位到图片位置
  Result := IncPointer(FFilePointer, FIndexArr[AIndex]);
end;

procedure TWilFile.SaveToFile(Index: Integer; const FileName: string);
var
  FileHeader: BITMAPFILEHEADER;
  InfoHeader: BITMAPINFOHEADER;
  ColorTableSize: Integer;
  InfoPtr: PImageInfo;
  PBits: PByte;
  F: file;
begin
  // 检查 AIndex 是否合法
  if (Index < 0) or (Index >= FImageCount) then
    raise Exception.Create('TWilFile.SaveToFile 数组超界!');

  // 图片信息指针
  InfoPtr := ImageInfo[Index];

  // 色彩表内存大小
  ColorTableSize := SizeOf(TRGBQuad) * 256;

  // 位图文件头
  FileHeader.bfType := MakeWord(Ord('B'), Ord('M'));
  FileHeader.bfSize := SizeOf(FileHeader) + SizeOf(InfoHeader) + ColorTableSize +
    InfoPtr^.Width * InfoPtr^.Height;
  FileHeader.bfReserved1 := 0;
  FileHeader.bfReserved2 := 0;
  FileHeader.bfOffBits := SizeOf(FileHeader) + SizeOf(InfoHeader) + ColorTableSize;

  // 位图信息头
  InfoHeader.biSize := SizeOf(InfoHeader);
  InfoHeader.biWidth := InfoPtr^.Width;
  InfoHeader.biHeight := InfoPtr^.Height;
  InfoHeader.biPlanes := 1;
  InfoHeader.biBitCount := 8;
  InfoHeader.biCompression := 0;
  InfoHeader.biSizeImage := 0;
  InfoHeader.biXPelsPerMeter := 0;
  InfoHeader.biYPelsPerMeter := 0;
  InfoHeader.biClrUsed := 0;
  InfoHeader.biClrImportant := 0;

  // 开始保存文件
  FileMode := fmOpenWrite;
  AssignFile(F, FileName);
  Rewrite(F, 1);

  try
    BlockWrite(F, FileHeader, SizeOf(FileHeader));
    BlockWrite(F, InfoHeader, SizeOf(InfoHeader));
    if ColorTableSize > 0 then
      BlockWrite(F, FMainColorTable^, ColorTableSize);
    PBits := IncPointer(InfoPtr, SizeOf(TImageInfo) - 4);
    BlockWrite(F, PBits^, InfoPtr^.Width * InfoPtr^.Height);
  finally
    CloseFile(F);
  end;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -