用户登录  | 
首 页技术文章软件发布广告价格
当前位置:传奇游戏服务端下载站传奇站长论坛资源网站程序技术文章文章资讯传奇架设教程传奇架设技术

wil格式文件调用函数

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2014-10-03 14:23:12
unit MirWil;

interface

uses
  SysUtils, Windows, DirectDraw, Assist, AdvDraw;

{------------------------------------------------------------------------------}
// 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;

{------------------------------------------------------------------------------}
// 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;         // 图片数量
    FBitmapInfo: TBitmapInfo256;  // 位图信息头部(用于 SetDIBitsToDevice)

    FDDSurfaceDesc2: TDDSurfaceDesc2;
    FSurfaces: array of IDirectDrawSurface7;
    FMainDirectDraw: IDirectDraw7;

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

    // Draw: 将 Index 位置的图片绘制至 Surface 的 X, Y 位置
    procedure Draw(Index: Integer; DstSurf: IDirectDrawSurface7; X, Y,
      DstWidth, DstHeight: Integer; Transparent: Boolean);
    // DrawEx: 将 Index 位置的图片绘制至 Surface 的 X, Y 位置, 包含 Image 的偏移位置
    procedure DrawEx(Index: Integer; DstSurf: IDirectDrawSurface7; X, Y,
      DstWidth, DstHeight: Integer; Transparent: Boolean);


    // BitBlt: 将 Index 位置的图片绘制至 DC 的 X, Y 位置
    procedure BitBlt(Index: Integer; DC: HDC; X, Y: Integer);
    // StretchBlt: 以缩放方式将图片绘制至 DC
    procedure StretchBlt(Index: Integer; DC: HDC; X, Y, Width, Height: Integer;
      ROP: Cardinal);
    // SaveTofile: 将索引位置的图片保存为 BMP 文件
    procedure SaveToFile(Index: Integer; const FileName: string);

    // 已打开的 WIL 文件名
    property FileName: string read FFileName;
    // 主调色板指针
    property MainColorTable: PRGBQuads read FMainColorTable;
    // IDirectDraw7, 用于创建 Surfaces 数组, 如果不指定也可以使用 BitBlt
    property MainDirectDraw: IDirectDraw7 read FMainDirectDraw write FMainDirectDraw;
    // 图片总数
    property ImageCount: Integer read FImageCount;
    // 图片的 Surface
    property Surfaces[AIndex: Integer]: IDirectDrawSurface7 read GetSurfaces;
    // 图片的信息
    property ImageInfo[AIndex: Integer]: PImageInfo read GetImageInfo;
  end;


implementation

{ TWilFile }

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

  FMainDirectDraw := ADirectDraw;
  
  // 读入图片索引文件
  LoadIndexFile;

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

  // 读入 WIL 文件头数据

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

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

  // 设置位图固定信息,以免每次 Blt 时设置
  // TODO: 位图文件头还可进一步压缩
  with FBitmapInfo.bmiHeader do
  begin
    biSize := SizeOf(TBitmapInfoHeader);
    // 这二项由读入图片后设置
    // biWidth := ImagePos^.Width;
    // biHeight := ImagePos^.Height;
    biPlanes := 1;
    biBitCount := 8;
    biCompression := BI_RGB;    // 注意,这里只使用未压缩数据
    biSizeImage := 0;           // 压缩时才需要 biSizeImage
    biXPelsPerMeter := 0;
    biYPelsPerMeter := 0;
    biClrUsed := 0;
    biClrImportant := 0;
  end;

  // 初始化 FDDSurfaceDesc2, 以免每次创建 Surface 时初始化
  // 此处不用 FillChar(FDDSurfaceDesc2)
  FDDSurfaceDesc2.dwSize := SizeOf(FDDSurfaceDesc2);
  FDDSurfaceDesc2.dwFlags := DDSD_CAPS or DDSD_WIDTH or DDSD_HEIGHT;
  FDDSurfaceDesc2.ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN or DDSCAPS_SYSTEMMEMORY;
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
    FSurfaces[I] := nil;
  SetLength(FSurfaces, 0);

  // 清除 FMainDirectDraw
  FMainDirectDraw := nil;

  // 关闭文件映射及相关句柄
  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;

procedure TWilFile.BitBlt(Index: Integer; DC: HDC; X, Y: Integer);
var
  ImageInfo: PImageInfo;
  PBits: Pointer;
begin
  // 检查 Index 是否合法
  if (Index < 0) or (Index >= FImageCount) then
    raise Exception.Create('TWilFile.BitBlt 数组超界!');

  // dingwei到图片位置
  ImageInfo := IncPointer(FFilePointer, FIndexArr[Index]);

  // 设置位图大小
  with FBitmapInfo.bmiHeader do
  begin
    biWidth := ImageInfo^.Width;
    biHeight := ImageInfo^.Height;
  end;

  // 填充调色板
  Move(MainColorTable^, FBitmapInfo.bmiColors, SizeOf(FBitMapInfo.bmiColors));

  // PBits 指向位图的 Bits
  PBits := IncPointer(ImageInfo, SizeOf(TImageInfo) - 4);

  // 直接将 DIB Bits 写到设备环境
  SetDIBitsToDevice(DC, X, Y, ImageInfo^.Width, ImageInfo^.Height, 0, 0, 0,
    ImageInfo^.Height, PBits, PBitmapInfo(PBitmapInfo256(@FBitmapInfo))^,


    DIB_RGB_COLORS);
end;

procedure TWilFile.StretchBlt(Index: Integer; DC: HDC; X, Y, Width, Height: Integer;
  ROP: Cardinal);
var
  ImageInfo: PImageInfo;
  PBits: Pointer;
begin
  // 检查 Index 是否合法
  if (Index < 0) or (Index >= FImageCount) then
    raise Exception.Create('TWilFile.StretchBlt 数组超界!');

  // dingwei到图片位置
  ImageInfo := IncPointer(FFilePointer, FIndexArr[Index]);

  // 设置位图大小
  with FBitmapInfo.bmiHeader do
  begin
    biWidth := ImageInfo^.Width;
    biHeight := ImageInfo^.Height;
  end;
  
  // 填充调色板
  Move(MainColorTable^, FBitmapInfo.bmiColors, SizeOf(FBitMapInfo.bmiColors));

  // PBits 指向位图的 Bits
  PBits := IncPointer(ImageInfo, SizeOf(TImageInfo) - 4);



  // 缩放方式将 DIB Bits 写到设备环境
  StretchDIBits(DC, X, Y, Width, Height, 0, 0, ImageInfo^.Width, ImageInfo^.Height,
    PBits, PBitmapInfo(PBitmapInfo256(@FBitmapInfo))^, DIB_RGB_COLORS, ROP);
end;

function TWilFile.GetSurfaces(AIndex: Integer): IDirectDrawSurface7;
var
  InfoPtr: PImageInfo;    // 图像信息, 使用临时变量将加快速度
  ColorKey: TDDColorKey;  // 透明色值
  DDSD: TDDSurfaceDesc2;  // 用于 Surface.Lock
  Y: Integer;             // Surface 的行值
  PBits: PByte;           // 指向 Bits 的指针
  DC: HDC;                // 用于 Surface.GetDC
begin
  // 检查 AIndex 是否合法
  if (AIndex < 0) or (AIndex >= FImageCount) then
    raise Exception.Create('TWilFile.GetSurfaces 数组超界!');

  // 检查 MainDirectDraw 是否存在
  if FMainDirectDraw = nil then
    raise Exception.Create('必须指定 MainDirectDraw!');

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

  // 否则创建新的 FSurface[AIndex]
  InfoPtr := ImageInfo[AIndex];

  FDDSurfaceDesc2.dwWidth := InfoPtr^.Width;
  FDDSurfaceDesc2.dwHeight := InfoPtr^.Height;

  if FMainDirectDraw.CreateSurface(FDDSurfaceDesc2, FSurfaces[AIndex], nil) <> DD_OK then
    raise Exception.Create('不能创建 WIL Surface!');

  if UseDIBSurface then // 写入表面位图方法之一:使用 DC, BitBlt
  begin
    if FSurfaces[AIndex].GetDC(DC) = DD_OK then
    begin


      SelectObject(DC, NULL_BRUSH);
      Rectangle(DC, 0, 0, ImageInfo[AIndex]^.Width, ImageInfo[AIndex]^.Height);
      BitBlt(AIndex, DC, 0, 0);
      FSurfaces[AIndex].ReleaseDC(DC);
    end
    else
    begin   // 如果获取 DC 失败, 则关闭当前 FSurface
      FSurfaces[AIndex] := nil;
      Exit;
    end;
  end
  else // 写入表面位图方法之二:直接拷贝 WIL Bits 数据至 Surface
  begin
    DDSD.dwSize := SizeOf(DDSD);
    if FSurfaces[AIndex].Lock(nil, DDSD, DDLOCK_WAIT, 0) <> DD_OK then Exit;
    // 这里比较奇怪,需要从位图的最后一行写入表面第一行,逆行序
    PBits := IncPointer(InfoPtr, (SizeOf(TImageInfo) - 4) +
      ((InfoPtr^.Height - 1) * InfoPtr^.Width));
    try
      for Y := 0 to InfoPtr^.Height - 1 do
      begin
        Move(PBits^, DDSD.lpSurface^, InfoPtr^.Width);
        Inc(PByte(DDSD.lpSurface), DDSD.lPitch);
        Dec(PBits, InfoPtr^.Width);
      end;
    finally
      FSurfaces[AIndex].Unlock(nil);
    end;
  end;

  // 设置 ColorKey (黑色)
  ColorKey.dwColorSpaceLowvalue := 0;
  ColorKey.dwColorSpaceHighvalue := 0;
  FSurfaces[AIndex].SetColorKey(DDCKEY_SRCBLT, @ColorKey);

  // 返回当前 Surface
  Result := FSurfaces[AIndex];
end;

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

  // dingwei到图片位置
  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;

procedure TWilFile.Draw(Index: Integer; DstSurf: IDirectDrawSurface7;
  X, Y, DstWidth, DstHeight: Integer; Transparent: Boolean);
var
  R: TRect;
  SizePtr: PImageInfo;
begin
  SizePtr := ImageInfo[Index];
  SetRect(R, X, Y, X + SizePtr.Width, Y + SizePtr.Height);
  FastBlt(DstSurf, X, Y, DstWidth, DstHeight, Surfaces[Index], SizePtr.Width,
    SizePtr.Height, Transparent);
end;

procedure TWilFile.DrawEx(Index: Integer; DstSurf: IDirectDrawSurface7;
  X, Y, DstWidth, DstHeight: Integer; Transparent: Boolean);
var
  SizePtr: PImageInfo;
begin
  SizePtr := ImageInfo[Index];
  FastBlt(DstSurf, X + SizePtr.PX, Y + SizePtr.PY, DstWidth, DstHeight,
    Surfaces[Index], SizePtr.Width, SizePtr.Height, Transparent);
end;

end.

Tags:

作者:佚名

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论

相关文章

传奇资源网提供最新传奇开区一条龙版本下载,本站声明:只更新最新最好的传奇服务端分享给大家。