--- oup/current/Global/OniImgClass.pas 2007/05/19 17:54:34 181 +++ oup/current/Global/OniImgClass.pas 2007/08/17 21:09:51 244 @@ -3,474 +3,247 @@ unit OniImgClass; interface uses Math, Dialogs, Types, SysUtils, Classes, Data, ConnectionManager, TypeDefs, - Imaging, ImagingTypes; - -type - TImgDataType = set of (DT_OniReverted, DT_Oni, DT_Decoded32); + Imaging, ImagingTypes, Graphics; type TOniImage = class private - FLoaded: Boolean; - FDataType: TImgDataType; - FData: TByteData; - FWidth, FHeight: Word; - FDepth: Byte; - FStoreType: Byte; - - FImage: TImageData; - - function ResizeImage(oldx, oldy: Integer; img: TByteData): TByteData; - procedure RevertImage; - procedure DecompressImage; + FImages: TDynImageDataArray; + function GetImage(MipGen: Integer): TImageData; + function GetWidth(MipGen: Integer): Integer; + function GetHeight(MipGen: Integer): Integer; + function GetImageFormat: TImageFormat; + procedure SetImageFormat(Format: TImageFormat); + function pGetImageFormatInfo: TImageFormatInfo; + function GetHasMipMaps: Boolean; protected public - property Image: TImageData Read FImage Write FImage; - property Loaded: Boolean Read FLoaded Write FLoaded; - property DataType: TImgDataType Read FDataType Write FDataType; - property Width: Word Read FWidth Write FWidth; - property Height: Word Read FHeight Write FHeight; - property Depth: Byte Read FDepth Write FDepth; - property StoreType: Byte Read FStoreType Write FStoreType; - property Data: TByteData Read FData Write FData; + property Images: TDynImageDataArray read FImages; + property Image[MipGen: Integer]: TImageData read GetImage; + property Width[MipGen: Integer]: Integer read GetWidth; + property Height[MipGen: Integer]: Integer read GetHeight; + property Format: TImageFormat read GetImageFormat write SetImageFormat; + property FormatInfo: TImageFormatInfo read pGetImageFormatInfo; + property HasMipMaps: Boolean read GetHasMipMaps; constructor Create; + procedure Free; + + function GetImageSize(MipMaps: Boolean): Integer; + + function LoadFromFile(filename: String): Boolean; + function WriteToFile(filename: String): Boolean; + procedure SaveDataToStream(MipMaps: Boolean; var Target: TStream); + procedure DrawOnCanvas(Canvas: TCanvas; Index: Integer); + function Load(ConnectionID, FileID: Integer): Boolean; - function LoadFromPSpc(ConnectionID, FileID: Integer): Boolean; function LoadFromTXMP(ConnectionID, FileID: Integer): Boolean; function LoadFromTXMB(ConnectionID, FileID: Integer): Boolean; - function GetImgSize(w,h, storetype: Integer): Integer; - function GetImageDataSize(fading: Boolean): Integer; - - procedure DecodeImageTo32bit; - - procedure GetAsData(var Target: TStream); overload; - procedure GetAsData(var Target: TByteData); overload; - procedure GetAs32bit(var Target: TStream); overload; - procedure GetAs32bit(var Target: TByteData); overload; - procedure GetAsBMP(var Target: TStream); overload; - procedure GetAsBMP(var Target: TByteData); overload; - function LoadFromBMP(filename: String): Boolean; - function WriteToBMP(filename: String): Boolean; - function GetMipMappedImage(var Target: TStream): Boolean; overload; - function GetMipMappedImage(var Target: TByteData): Boolean; overload; + function LoadFromPSpc(ConnectionID, FileID: Integer): Boolean; published end; implementation -//uses Functions; -uses Img_DDSTypes; +uses Img_DDSTypes, ImagingComponents; -constructor TOniImage.Create; +function TOniImage.GetImage(MipGen: Integer): TImageData; begin - Self.FLoaded := False; - Self.FDataType := []; - SetLength(Self.FData, 0); - Self.FWidth := 0; - Self.FHeight := 0; - Self.FDepth := 0; - Self.FStoreType := 0; - - InitImage(FImage); + if MipGen <= Length(FImages) then + begin + InitImage(Result); + CloneImage(FImages[MipGen-1], Result); + end; end; +function TOniImage.GetWidth(MipGen: Integer): Integer; +begin + if MipGen <= Length(FImages) then + Result := FImages[MipGen-1].Width + else + Result := -1; +end; -function TOniImage.ResizeImage(oldx, oldy: Integer; img: TByteData): TByteData; -var - i, j: Integer; - col, row, row_orig: Integer; +function TOniImage.GetHeight(MipGen: Integer): Integer; begin - SetLength(Result, (oldx div 2) * (oldy div 2) * (Self.FDepth div 8)); - row_orig := 0; - row := 0; - col := 0; - for i := 0 to (oldx * oldy) - 1 do - begin - if ((i mod oldx) = 0) and (i > 0) then - begin - Inc(row_orig); - if (row_orig mod 2) = 0 then - begin - Inc(row); - col := 0; - end; - end; - if (row_orig mod 2) = 0 then - begin - if (i mod 2) = 0 then - begin - for j := 0 to (Self.FDepth div 8) - 1 do - Result[((row * (oldx div 2)) + col) * (Self.FDepth div 8) + j] := - img[(i * (Self.FDepth div 8)) + j]; - Inc(col); - end; - end; - end; + if MipGen <= Length(FImages) then + Result := FImages[MipGen-1].Height + else + Result := -1; end; +function TOniImage.GetImageFormat: TImageFormat; +begin + if Length(FImages) > 0 then + Result := FImages[0].Format + else + Result := ifUnknown; +end; - -procedure TOniImage.RevertImage; +procedure TOniImage.SetImageFormat(Format: TImageFormat); var - x, y, i: Integer; - tempd: TByteData; + i: Integer; begin - SetLength(tempd, Self.FWidth * Self.FHeight * (Self.FDepth div 8)); - for y := 0 to Self.FHeight - 1 do - for x := 0 to Self.FWidth - 1 do - for i := 0 to (Self.FDepth div 8) - 1 do - tempd[((Self.FWidth * (Self.FHeight - 1 - y) + x) * (Self.FDepth div 8)) + i] := - Self.FData[(Self.FWidth * y + x) * (Self.FDepth div 8) + i]; - for x := 0 to High(tempd) do - Self.FData[x] := tempd[x]; - if DT_OniReverted in Self.FDataType then - Self.FDataType := Self.FDataType - [DT_OniReverted] - else - Self.FDataType := Self.FDataType + [DT_OniReverted]; + if Length(FImages) > 0 then + for i := 0 to High(FImages) do + ConvertImage(FImages[i], Format); end; +function TOniImage.pGetImageFormatInfo: TImageFormatInfo; +begin + if Length(FImages) > 0 then + GetImageFormatInfo(FImages[0].Format, Result); +end; -procedure TOniImage.DecodeImageTo32bit; -var - x, y: Integer; - tempd: TByteData; +function TOniImage.GetHasMipMaps: Boolean; begin - if not (DT_Decoded32 in Self.FDataType) then - begin - SetLength(tempd, Self.FWidth * Self.FHeight * 4); - case Self.FStoreType of - 0: // 16bit, RGB444, A4? - begin - for y := 0 to Self.FHeight - 1 do - begin - for x := 0 to Self.FWidth - 1 do - begin - tempd[((Self.FWidth * y + x) * 4) + 0] := - Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and - $000F) / $000F * 255); - tempd[((Self.FWidth * y + x) * 4) + 1] := - Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and - $00F0) / $00F0 * 255); - tempd[((Self.FWidth * y + x) * 4) + 2] := - Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and - $0F00) / $0F00 * 255); - tempd[((Self.FWidth * y + x) * 4) + 3] := 0; - end; - end; - end; - 1, 2: // 16bit, RGB555, A1? - begin - for y := 0 to Self.FHeight - 1 do - begin - for x := 0 to Self.FWidth - 1 do - begin - tempd[((Self.FWidth * y + x) * 4) + 0] := - Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and - $001F) / $001F * 255); - tempd[((Self.FWidth * y + x) * 4) + 1] := - Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and - $03E0) / $03E0 * 255); - tempd[((Self.FWidth * y + x) * 4) + 2] := - Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and - $7C00) / $7C00 * 255); - tempd[((Self.FWidth * y + x) * 4) + 3] := 0; - end; - end; - end; - 8: // 32bit, RGB888, A8? - begin end; - 9: // Compressed, RGB565 - begin - DecompressImage; - end; - end; - Self.FDepth := 32; - if (Self.FStoreType <> 9) and (Self.FStoreType <> 8) then - begin - SetLength(Self.FData, Length(tempd)); - for x := 0 to High(tempd) do - Self.FData[x] := tempd[x]; - end; - Self.FStoreType := 8; - if DT_Oni in Self.FDataType then - Self.FDataType := Self.FDataType - [DT_Oni]; - Self.FDataType := Self.FDataType + [DT_Decoded32]; - end; - if DT_OniReverted in Self.FDataType then - Self.RevertImage; + Result := Length(FImages) > 1; end; -procedure TOniImage.DecompressImage; -type - Tcolor = record - RGBb: Byte; - RGBg: Byte; - RGBr: Byte; - RGBa: Byte; - end; -var - i, j, x, y: Integer; - color: array[1..4] of Tcolor; - pixel: array[1..16] of Byte; - tempd: TByteData; +constructor TOniImage.Create; begin - x := 0; - y := 0; - SetLength(tempd, Self.FWidth * Self.FHeight * 4); - for i := 0 to ((Self.FWidth * Self.FHeight) div 16) - 1 do - begin - Color[1].RGBb := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $001F) / - $001F * 255); - Color[1].RGBg := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $07E0) / - $07E0 * 255); - Color[1].RGBr := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $F800) / - $F800 * 255); - Color[1].RGBa := 255; - Color[2].RGBb := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $001F) / - $001F * 255); - Color[2].RGBg := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $07E0) / - $07E0 * 255); - Color[2].RGBr := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $F800) / - $F800 * 255); - Color[2].RGBa := 255; - Color[3].RGBb := Round(Color[1].RGBb / 3 * 2 + Color[2].RGBb / 3); - Color[3].RGBg := Round(Color[1].RGBg / 3 * 2 + Color[2].RGBg / 3); - Color[3].RGBr := Round(Color[1].RGBr / 3 * 2 + Color[2].RGBr / 3); - Color[3].RGBa := 255; - Color[4].RGBb := Round(Color[1].RGBb / 3 + Color[2].RGBb / 3 * 2); - Color[4].RGBg := Round(Color[1].RGBg / 3 + Color[2].RGBg / 3 * 2); - Color[4].RGBr := Round(Color[1].RGBr / 3 + Color[2].RGBr / 3 * 2); - Color[4].RGBa := 255; - Pixel[1] := Round((Self.FData[(i * 8) + 4] and $C0) / $40 + 1); - Pixel[2] := Round((Self.FData[(i * 8) + 4] and $30) / $10 + 1); - Pixel[3] := Round((Self.FData[(i * 8) + 4] and $0C) / $04 + 1); - Pixel[4] := Round((Self.FData[(i * 8) + 4] and $03) + 1); - Pixel[5] := Round((Self.FData[(i * 8) + 5] and $C0) / $40 + 1); - Pixel[6] := Round((Self.FData[(i * 8) + 5] and $30) / $10 + 1); - Pixel[7] := Round((Self.FData[(i * 8) + 5] and $0C) / $04 + 1); - Pixel[8] := Round((Self.FData[(i * 8) + 5] and $03) + 1); - Pixel[9] := Round((Self.FData[(i * 8) + 6] and $C0) / $40 + 1); - Pixel[10] := Round((Self.FData[(i * 8) + 6] and $30) / $10 + 1); - Pixel[11] := Round((Self.FData[(i * 8) + 6] and $0C) / $04 + 1); - Pixel[12] := Round((Self.FData[(i * 8) + 6] and $03) + 1); - Pixel[13] := Round((Self.FData[(i * 8) + 7] and $C0) / $40 + 1); - Pixel[14] := Round((Self.FData[(i * 8) + 7] and $30) / $10 + 1); - Pixel[15] := Round((Self.FData[(i * 8) + 7] and $0C) / $04 + 1); - Pixel[16] := Round((Self.FData[(i * 8) + 7] and $03) + 1); - for j := 0 to 3 do - begin - tempd[((y + 3) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[16 - j]].RGBb; - tempd[((y + 3) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[16 - j]].RGBg; - tempd[((y + 3) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[16 - j]].RGBr; - tempd[((y + 3) * Self.FWidth + x + j) * 4 + 3] := 0; - end; - for j := 0 to 3 do - begin - tempd[((y + 2) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[12 - j]].RGBb; - tempd[((y + 2) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[12 - j]].RGBg; - tempd[((y + 2) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[12 - j]].RGBr; - tempd[((y + 2) * Self.FWidth + x + j) * 4 + 3] := 0; - end; - for j := 0 to 3 do - begin - tempd[((y + 1) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[8 - j]].RGBb; - tempd[((y + 1) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[8 - j]].RGBg; - tempd[((y + 1) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[8 - j]].RGBr; - tempd[((y + 1) * Self.FWidth + x + j) * 4 + 3] := 0; - end; - for j := 0 to 3 do - begin - tempd[((y + 0) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[4 - j]].RGBb; - tempd[((y + 0) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[4 - j]].RGBg; - tempd[((y + 0) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[4 - j]].RGBr; - tempd[((y + 0) * Self.FWidth + x + j) * 4 + 3] := 0; - end; - x := x + 4; - if x = Self.FWidth then - begin - y := y + 4; - x := 0; - end; - end; - SetLength(Self.FData, Length(tempd)); - for i := 0 to High(tempd) do - Self.FData[i] := tempd[i]; - Self.FStoreType := 8; - Self.FDepth := 32; - Self.FDataType := Self.FDataType - [DT_Oni] + [DT_Decoded32]; end; +procedure TOniImage.Free; +begin + FreeImagesInArray(FImages); +end; -function TOniImage.Load(ConnectionID, FileID: Integer): Boolean; +function TOniImage.GetImageSize(MipMaps: Boolean): Integer; var - FileInfo: TFileInfo; + i: Integer; begin - FileInfo := ConManager.Connection[ConnectionID].GetFileInfo(fileid); - if FileInfo.Extension = 'PSpc' then - Result := LoadFromPSpc(ConnectionID, fileid) - else if FileInfo.Extension = 'TXMB' then - Result := LoadFromTXMB(ConnectionID, fileid) - else if FileInfo.Extension = 'TXMP' then - Result := LoadFromTXMP(ConnectionID, fileid) + if Length(FImages) > 0 then + begin + Result := FImages[0].Size; + if mipmaps then + for i := 1 to High(FImages) do + Result := Result + FImages[i].Size; + end else - Result := False; + Result := -1; end; -function TOniImage.LoadFromPSpc(ConnectionID, FileID: Integer): Boolean; -type - TPoint = packed record - X, Y: Word; - end; +function TOniImage.LoadFromFile(filename: String): Boolean; +begin + Result := LoadMultiImageFromFile(filename, FImages); + if not Result then + ShowMessage('Couldn''t load image file'); +end; - TPSpc = packed record - p1: array[0..8] of TPoint; - p2: array[0..8] of TPoint; - TXMP: Integer; - end; - TPart = packed record - x_txmp, y_txmp: Word; - x_pspc, y_pspc: Word; - w, h: Word; - imgdata: TByteData; - used: Boolean; - end; -const - PartMatch: array[0..8] of Byte = (0, 3, 6, 1, 4, 7, 2, 5, 8); +function TOniImage.WriteToFile(filename: String): Boolean; +begin + Result := SaveMultiImageToFile(filename, FImages); +end; + + + +procedure TOniImage.DrawOnCanvas(Canvas: TCanvas; Index: Integer); var - x, y, pixel: Word; - i: Integer; + singleimg: TImageData; + rect: TRect; +begin + InitImage(singleimg); + CloneImage(FImages[Index-1], singleimg); + ConvertImage(singleimg, ifX8R8G8B8); + rect.Left := 0; + rect.Top := 0; + rect.Right := singleimg.Width - 1; + rect.Bottom := singleimg.Height - 1; + Canvas.Brush.Color := $C8D0D4; + Canvas.FillRect(Canvas.ClipRect); + DisplayImageData(Canvas, rect, singleimg, rect); + FreeImage(singleimg); +end; - PSpc: TPSpc; - txmpimg: TOniImage; - txmpdata: TByteData; - parts: array[0..8] of TPart; - part: Byte; - cols: array[0..2] of Word; - rows: array[0..2] of Word; - col, row: Byte; + + +procedure TOniImage.SaveDataToStream(MipMaps: Boolean; var Target: TStream); +var + images: TDynImageDataArray; + mem: TMemoryStream; + i: Integer; begin - ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $08, SizeOf(PSpc), @PSpc); - PSpc.TXMP := PSpc.TXMP div 256; - if PSpc.TXMP = 0 then - begin - Result := False; + if Length(FImages) = 0 then Exit; - end; - txmpimg := TOniImage.Create; - txmpimg.LoadFromTXMP(ConnectionID, PSpc.TXMP); - txmpimg.DecodeImageTo32bit; -// txmpimg.WriteToBMP('C:\file.bmp'); - txmpimg.GetAs32bit(txmpdata); -{ ShowMessage(IntToStr(txmpimg.Width)+'x'+IntToStr(txmpimg.Height)); - for i:=0 to High(txmpdata) do - txmpimg.Data[i]:=txmpdata[i]; - txmpimg.WriteToBMP('D:\file2.bmp'); -} - with PSpc do + if MipMaps then begin - for i := 0 to 2 do + if Length(FImages) = 1 then begin - cols[i] := 0; - rows[i] := 0; - end; - for i := 0 to 8 do - begin - part := PartMatch[i]; - col := i div 3; - row := i mod 3; - if (p2[i].X > 0) or (p2[i].Y > 0) then + if not GenerateMipMaps(FImages[0], 0, images) then begin - parts[part].x_txmp := p1[i].X - 1; - parts[part].y_txmp := p1[i].Y - 1; - parts[part].x_pspc := 0; - if col > 0 then - for x := 0 to col - 1 do - Inc(parts[part].x_pspc, cols[x]); - parts[part].y_pspc := 0; - if row > 0 then - for y := 0 to row - 1 do - Inc(parts[part].y_pspc, rows[y]); - parts[part].w := p2[i].X - p1[i].X + 1; - parts[part].h := p2[i].Y - p1[i].Y + 1; - parts[part].used := True; - cols[col] := parts[part].w; - rows[row] := parts[part].h; - SetLength(parts[part].imgdata, parts[part].w * parts[part].h * 4); - for y := 0 to parts[part].h - 1 do - begin - for x := 0 to parts[part].w - 1 do - begin - for pixel := 0 to 3 do - begin - parts[part].imgdata[(y * parts[part].w + x) * 4 + pixel] := - txmpdata[((parts[part].y_txmp + y) * txmpimg.Width + - parts[part].x_txmp + x) * 4 + pixel]; - end; - end; - end; - end - else - begin - parts[part].used := False; + ShowMessage('Could not generate MipMaps'); + Exit; end; + end + else + begin + SetLength(images, Length(FImages)); + for i := 0 to High(FImages) do + CloneImage(FImages[i], images[i]); end; - - end; - - txmpimg.Free; - txmpimg := TOniImage.Create; - for i := 0 to 8 do + mem := TMemoryStream.Create; + if not SaveMultiImageToStream('dds', mem, images) then + begin + ShowMessage('Could not save images to stream'); + Exit; + end; + FreeImagesInArray(images); + end + else begin - if parts[i].used then + mem := TMemoryStream.Create; + if not SaveImageToStream('dds', mem, FImages[0]) then begin - SetLength(txmpimg.FData, Length(parts[i].imgdata)); - for pixel := 0 to High(parts[i].imgdata) do - txmpimg.Data[pixel] := parts[i].imgdata[pixel]; - txmpimg.Width := parts[i].w; - txmpimg.Height := parts[i].h; - txmpimg.StoreType := 8; - txmpimg.DataType := [DT_Decoded32]; - txmpimg.Depth := 32; - txmpimg.WriteToBMP('M:\' + IntToStr(i) + '.bmp'); + ShowMessage('Could not save image to stream'); + Exit; end; end; - txmpimg.Free; + if not Assigned(Target) then + Target := TMemoryStream.Create; + + mem.Seek(128, soFromBeginning); + Target.CopyFrom(mem, mem.Size - 128); + mem.Free; + Target.Seek(0, soFromBeginning); +end; - Self.FWidth := 0; - Self.FHeight := 0; - for i := 0 to 2 do - begin - Inc(Self.FWidth, cols[i]); - Inc(Self.FHeight, rows[i]); - end; - SetLength(Self.FData, Self.FWidth * Self.FHeight * 4); - //Combine data parts - Self.FDepth := 32; - Self.FStoreType := 8; - Self.FDataType := [DT_Decoded32]; - // Self.RevertImage; + + +function TOniImage.Load(ConnectionID, FileID: Integer): Boolean; +var + FileInfo: TFileInfo; +begin + FileInfo := ConManager.Connection[ConnectionID].GetFileInfo(fileid); + if FileInfo.Extension = 'PSpc' then + Result := LoadFromPSpc(ConnectionID, fileid) + else if FileInfo.Extension = 'TXMB' then + Result := LoadFromTXMB(ConnectionID, fileid) + else if FileInfo.Extension = 'TXMP' then + Result := LoadFromTXMP(ConnectionID, fileid) + else + Result := False; end; @@ -483,34 +256,33 @@ var hdr: TDDSDXTHeader; imginfo: Integer; x,y, i: Integer; + + _width, _height: Word; + _storetype: Byte; + _depth: Byte; begin - Result := True; - ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8C, SizeOf(Self.FWidth), @Self.FWidth); - ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8E, SizeOf(Self.FHeight), @Self.FHeight); - ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $90, SizeOf(Self.FStoreType), @Self.FStoreType); + Result := False; + ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8C, SizeOf(_width), @_width); + ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8E, SizeOf(_height), @_height); + ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $90, SizeOf(_storetype), @_storetype); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $88, SizeOf(imginfo), @imginfo); if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $9C, SizeOf(img_addr), @img_addr) else ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $A0, SizeOf(img_addr), @img_addr); - case Self.FStoreType of + case _storetype of 0, 1, 2: - Self.FDepth := 16; - 8: - Self.FDepth := 32; + _depth := 16; + 7, 8: + _depth := 32; 9: - Self.FDepth := 16; + _depth := 16; else Result := False; Exit; end; - if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then - ConManager.Connection[ConnectionID].LoadRawFile(fileid, $9C, TStream(data)) - else - ConManager.Connection[ConnectionID].LoadRawFile(fileid, $A0, TStream(data)); - with hdr do begin FOURCC := 'DDS '; @@ -518,405 +290,312 @@ begin begin Size := 124; Flags := DDSD_CAPS or DDSD_PIXELFORMAT or DDSD_WIDTH or DDSD_HEIGHT; - if FStoreType = 9 then + if _storetype = 9 then Flags := Flags or DDSD_LINEARSIZE else Flags := Flags or DDSD_PITCH; if (imginfo and $01) > 0 then Flags := Flags or DDSD_MIPMAPCOUNT; - Height := FHeight; - Width := FWidth; - if FStoreType = 9 then - PitchOrLinearSize := FWidth * FHeight div 2 + Height := _height; + Width := _width; + if _storetype = 9 then + PitchOrLinearSize := width * height div 2 else - PitchOrLinearSize := FWidth * FDepth div 2; + PitchOrLinearSize := width * _depth div 8; Depth := 0; MipMapCount := 1; - x := FWidth; - y := FHeight; - while (x > 1) and (y > 1) do + if (imginfo and $01) > 0 then begin - x := x div 2; - y := y div 2; - Inc(MipMapCount); + x := width; + y := height; + while (x > 1) and (y > 1) do + begin + x := x div 2; + y := y div 2; + Inc(MipMapCount); + end; end; for i := 1 to 11 do Reserved[i] := 0; with PIXELFORMAT do begin Size := 32; - if FStoreType = 9 then + if _storetype = 9 then Flags := DDPF_FOURCC else Flags := DDPF_RGB; + if _storetype in [0, 2] then + Flags := Flags or DDPF_ALPHAPIXELS; + if _storetype = 9 then + FOURCC := 'DXT1' + else + begin + RGBBitCount := _depth; + case _storetype of + 0: begin + RBitMask := $0F00; + GBitMask := $00F0; + BBitMask := $000F; + AlphaBitMask := $F000; + end; + 1, 2: begin + RBitMask := $7C00; + GBitMask := $03E0; + BBitMask := $001F; + if _storetype = 2 then + AlphaBitMask := $8000 + else + AlphaBitMask := $0000; + end; + 8: begin + RBitMask := $00FF0000; + GBitMask := $0000FF00; + BBitMask := $000000FF; + AlphaBitMask := $00000000; + end; + end; + end; + end; + with DDSCAPS2 do + begin + Caps1 := DDSCAPS_TEXTURE; + if (imginfo and $01) > 0 then + Caps1 := Caps1 or DDSCAPS_COMPLEX or DDSCAPS_MIPMAP; + Caps2 := 0; + Reserved[1] := 0; + Reserved[2] := 0; end; end; - end; - LoadImageFromStream(data, FImage); -{ + end; + + data := TMemoryStream.Create; + data.Write(hdr, SizeOf(hdr)); if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then - ConManager.Connection[ConnectionID].LoadRawFile(fileid, $9C, FData) + ConManager.Connection[ConnectionID].LoadRawFile(fileid, $9C, TStream(data)) else - ConManager.Connection[ConnectionID].LoadRawFile(fileid, $A0, FData); -} - Self.FDataType := [DT_OniReverted, DT_Oni]; + ConManager.Connection[ConnectionID].LoadRawFile(fileid, $A0, TStream(data)); + + data.Seek(0, soFromBeginning); + Result := LoadMultiImageFromStream(data, FImages); + data.Free; + + if not result then + begin + ShowMessage('Error while loading file' + #13#10 + DetermineStreamFormat(data)); + end; end; + function TOniImage.LoadFromTXMB(ConnectionID, FileID: Integer): Boolean; var - i, x, y, x2, y2, pixelid, imgid: Integer; + i, x, y, imgid: Integer; rows, cols: Word; linkcount: Integer; link: Integer; - images_decoded: array of TOniImage; + images: array of TOniImage; x_start, y_start: Integer; + + width, height: Word; begin - ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $10, SizeOf(Self.FWidth), @Self.FWidth); - ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $12, SizeOf(Self.FHeight), @Self.FHeight); + Result := False; + ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $10, SizeOf(width), @width); + ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $12, SizeOf(height), @height); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $18, SizeOf(cols), @cols); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1A, SizeOf(rows), @rows); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, SizeOf(linkcount), @linkcount); - SetLength(images_decoded, linkcount); + SetLength(images, linkcount); for i := 0 to linkcount - 1 do begin ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + i * 4, SizeOf(link), @link); link := link div 256; - images_decoded[i] := TOniImage.Create; - images_decoded[i].LoadFromTXMP(ConnectionID, link); - images_decoded[i].DecodeImageTo32bit; - images_decoded[i].RevertImage; + images[i] := TOniImage.Create; + images[i].LoadFromTXMP(ConnectionID, link); end; - SetLength(Self.FData, Self.FWidth * Self.FHeight * 4); + SetLength(FImages, 1); + NewImage(width, height, images[0].Format {ifA1R5G5B5}, FImages[0]); for y := 0 to rows - 1 do begin for x := 0 to cols - 1 do begin - imgid := y * cols + x; + imgid := y * cols + x; x_start := 0; y_start := 0; for i := 0 to x do if i < x then - x_start := x_start + images_decoded[i].Width; + x_start := x_start + images[i].Image[1].Width; for i := 0 to y do if i < y then - y_start := y_start + images_decoded[i].Height; - for y2 := 0 to images_decoded[imgid].Height - 1 do - begin - for x2 := 0 to images_decoded[imgid].Width - 1 do - begin - if ((x_start + x2) < Self.FWidth) and ((y_start + y2) < Self.FHeight) then - begin - pixelid := y_start * Self.FWidth + x_start + y2 * Self.FWidth + x2; - Self.FData[pixelid * 4 + 0] := - images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 0]; - Self.FData[pixelid * 4 + 1] := - images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 1]; - Self.FData[pixelid * 4 + 2] := - images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 2]; - Self.FData[pixelid * 4 + 3] := - images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 3]; - end; - end; - end; + y_start := y_start + images[i].Image[1].Height; + CopyRect(images[imgid].Image[1], 0, 0, images[imgid].Image[1].Width, + images[imgid].Image[1].Height, FImages[0], x_start, y_start); end; end; for i := 0 to linkcount - 1 do - images_decoded[i].Free; - Self.FDepth := 32; - Self.FStoreType := 8; - Self.FDataType := [DT_Decoded32]; - Self.RevertImage; + images[i].Free; + Result := True; end; -function TOniImage.GetImgSize(w,h, storetype: Integer): Integer; -begin - case storetype of - 0, 1, 2: - Result := w*h*2; - 8: - Result := w*h*4; - 9: - Result := Max(1, w div 4) * Max(1, h div 4) * 8; - else - Result := -1; + + +function TOniImage.LoadFromPSpc(ConnectionID, FileID: Integer): Boolean; +type + TPoint = packed record + X, Y: Word; end; -end; + TPSpc = packed record + p1: array[0..8] of TPoint; + p2: array[0..8] of TPoint; + TXMP: Integer; + end; -function TOniImage.GetImageDataSize(fading: Boolean): Integer; + TPart = packed record + x_txmp, y_txmp: Word; + x_pspc, y_pspc: Word; + w, h: Word; + imgdata: TImageData; + used: Boolean; + end; +const + PartMatch: array[0..8] of Byte = (0, 3, 6, 1, 4, 7, 2, 5, 8); + stretch_x: Integer = 1; + stretch_y: Integer = 1; var - size: Integer; x, y: Word; -begin - x := Self.FWidth; - y := Self.FHeight; - size := GetImgSize(x, y, FStoreType); - if fading then - begin - repeat - x := Max(x div 2, 1); - y := Max(y div 2, 1); - size := size + GetImgSize(x, y, FStoreType); - until (x = 1) and (y = 1); - end; - Result := size; -end; - + i: Integer; + PSpc: TPSpc; + txmpimg: TOniImage; + parts: array[0..8] of TPart; + part: Byte; + cols: array[0..2] of Word; + rows: array[0..2] of Word; + col, row: Byte; -procedure TOniImage.GetAsData(var Target: TStream); -var - revert: Boolean; + pspcimage: TImageData; begin - // if not (DT_Decoded32 in Self.FDataType) then - // Self.DecodeImage; - if not (DT_OniReverted in Self.FDataType) then + ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $08, SizeOf(PSpc), @PSpc); + PSpc.TXMP := PSpc.TXMP div 256; + if PSpc.TXMP = 0 then begin - revert := True; - Self.RevertImage; - end - else - revert := False; - if not Assigned(Target) then - Target := TMemoryStream.Create; - Target.Write(FData[0], Length(FData)); - Target.Seek(0, soFromBeginning); - if revert then - Self.RevertImage; -end; - -procedure TOniImage.GetAsData(var Target: TByteData); -var - mem: TStream; -begin - mem := TMemoryStream.Create; - GetAsData(mem); - SetLength(Target, mem.Size); - mem.Read(Target[0], mem.Size); - mem.Free; -end; + Result := False; + Exit; + end; + txmpimg := TOniImage.Create; + txmpimg.Load(ConnectionID, PSpc.TXMP); + CloneImage(txmpimg.Image[1], pspcimage); + txmpimg.Free; + Result := False; -procedure TOniImage.GetAs32bit(var Target: TStream); -begin - if not (DT_Decoded32 in Self.FDataType) then - Self.DecodeImageTo32bit; - if not Assigned(Target) then - Target := TMemoryStream.Create; - Target.Write(FData[0], Length(FData)); - Target.Seek(0, soFromBeginning); -end; + with pspc do + begin + for i := 0 to 2 do + begin + cols[i] := 0; + rows[i] := 0; + end; + for i := 0 to 8 do + begin + part := PartMatch[i]; + col := i div 3; + row := i mod 3; + if (p2[i].X > 0) or (p2[i].Y > 0) then + begin + parts[part].x_txmp := p1[i].X;// - 1; + parts[part].y_txmp := p1[i].Y;// - 1; + parts[part].x_pspc := 0; + if col > 0 then + for x := 0 to col - 1 do + Inc(parts[part].x_pspc, cols[x]); + parts[part].y_pspc := 0; + if row > 0 then + for y := 0 to row - 1 do + Inc(parts[part].y_pspc, rows[y]); + parts[part].w := Max(p2[i].X - p1[i].X, 1);// + 1; + parts[part].h := Max(p2[i].Y - p1[i].Y, 1);// + 1; + parts[part].used := True; + cols[col] := parts[part].w; + rows[row] := parts[part].h; -procedure TOniImage.GetAs32bit(var Target: TByteData); -var - mem: TStream; -begin - mem := TMemoryStream.Create; - GetAs32bit(mem); - SetLength(Target, mem.Size); - mem.Read(Target[0], mem.Size); - mem.Free; -end; + NewImage(parts[part].w, parts[part].h, pspcimage.Format, parts[part].imgdata); + CopyRect(pspcimage, + parts[part].x_txmp, parts[part].y_txmp, parts[part].w, parts[part].h, + parts[part].imgdata, 0, 0); + end + else + begin + parts[part].used := False; + end; + end; -procedure TOniImage.GetAsBMP(var Target: TByteData); -const - BMPheader: array[0..53] of Byte = - ($42, $4D, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, - 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, $18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); -var - i, x, y: Integer; -begin - if not (DT_Decoded32 in Self.FDataType) then - Self.DecodeImageTo32bit; + end; - SetLength(Target, Self.FWidth * Self.FHeight * 3 + 54); - for y := 0 to Self.FHeight - 1 do + for i := 0 to 8 do begin - for x := 0 to Self.FWidth - 1 do + if parts[i].used then begin - Target[((Self.FWidth * y + x) * 3) + 0 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 0]; - Target[((Self.FWidth * y + x) * 3) + 1 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 1]; - Target[((Self.FWidth * y + x) * 3) + 2 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 2]; +// SaveImageToFile('M:\' + IntToStr(i) + '.bmp', parts[i].imgdata); end; end; - for i := 0 to High(BMPheader) do - Target[i] := BMPheader[i]; - Target[2] := ((Self.FWidth * Self.FHeight * 3 + 54) and $000000FF) div $1; - Target[3] := ((Self.FWidth * Self.FHeight * 3 + 54) and $0000FF00) div $100; - Target[4] := ((Self.FWidth * Self.FHeight * 3 + 54) and $00FF0000) div $10000; - Target[5] := ((Self.FWidth * Self.FHeight * 3 + 54) and $FF000000) div $1000000; - Target[18] := (Self.FWidth and $000000FF) div $1; - Target[19] := (Self.FWidth and $0000FF00) div $100; - Target[20] := (Self.FWidth and $00FF0000) div $10000; - Target[21] := (Self.FWidth and $FF000000) div $1000000; - Target[22] := (Self.FHeight and $000000FF) div $1; - Target[23] := (Self.FHeight and $0000FF00) div $100; - Target[24] := (Self.FHeight and $00FF0000) div $10000; - Target[25] := (Self.FHeight and $FF000000) div $1000000; - Target[34] := ((Self.FWidth * Self.FHeight * 3) and $000000FF) div $1; - Target[35] := ((Self.FWidth * Self.FHeight * 3) and $0000FF00) div $100; - Target[36] := ((Self.FWidth * Self.FHeight * 3) and $00FF0000) div $10000; - Target[37] := ((Self.FWidth * Self.FHeight * 3) and $FF000000) div $1000000; -end; - - -procedure TOniImage.GetAsBMP(var Target: TStream); -var - data: TByteData; - streampos: Integer; -begin - GetAsBMP(data); - streampos := Target.Position; - Target.Write(data[0], Length(data)); - Target.Seek(streampos, soFromBeginning); -end; - + SetLength(FImages, 1); + x := cols[0] + cols[1] * stretch_x + cols[2]; + y := rows[0] + rows[1] * stretch_y + rows[2]; -function TOniImage.LoadFromBMP(filename: String): Boolean; -var - filestream: TFileStream; - tempd: TByteData; - - x, y: Integer; -begin - filestream := TFileStream.Create(filename, fmOpenRead); - SetLength(tempd, filestream.Size); - filestream.Read(tempd[0], filestream.Size); - filestream.Free; + NewImage(x, y, pspcimage.Format, FImages[0]); - if not ((tempd[00] = $42) and (tempd[01] = $4D)) then - begin - Result := False; - ShowMessage('Not a standard 24bit bitmap'); - Exit; - end; - if not (tempd[10] = 54) then - begin - Result := False; - ShowMessage('Imagedata has to start at 0x54'); - Exit; - end; - if not (tempd[14] = 40) then - begin - Result := False; - ShowMessage('Second bitmap header has to have 40 bytes'); - Exit; - end; - if not (tempd[28] = 24) then - begin - Result := False; - ShowMessage('Bitmap has to have 24bits'); - Exit; - end; - if not (tempd[30] = 0) then + x := 0; + for col := 0 to 2 do begin - Result := False; - ShowMessage('Bitmap has to be uncompressed'); - Exit; - end; - - Self.FWidth := tempd[18] + tempd[19] * 256 + tempd[20] * 256 * 256 + tempd[21] * 256 * 256 * 256; - Self.FHeight := tempd[22] + tempd[23] * 256 + tempd[24] * 256 * 256 + tempd[25] * 256 * 256 * 256; - Self.FDepth := 32; - Self.FStoreType := 8; - - SetLength(Self.FData, Self.FWidth * Self.FHeight * Self.FDepth div 8); - for y := 0 to Self.FHeight - 1 do - begin - for x := 0 to Self.FWidth - 1 do - begin - Self.FData[((Self.FWidth * y + x) * 4) + 0] := tempd[54 + (Self.FWidth * y + x) * 3 + 0]; - Self.FData[((Self.FWidth * y + x) * 4) + 1] := tempd[54 + (Self.FWidth * y + x) * 3 + 1]; - Self.FData[((Self.FWidth * y + x) * 4) + 2] := tempd[54 + (Self.FWidth * y + x) * 3 + 2]; - Self.FData[((Self.FWidth * y + x) * 4) + 3] := 0; + y := 0; + for row := 0 to 2 do + begin + part := row*3 + col; + if parts[part].used then + begin + if (row = 1) and (col = 1) then + StretchRect(parts[part].imgdata, 0, 0, parts[part].w, parts[part].h, + FImages[0], x, y, parts[part].w * stretch_x, parts[part].h * stretch_y, rfNearest) + else + if (row = 1) then + StretchRect(parts[part].imgdata, 0, 0, parts[part].w, parts[part].h, + FImages[0], x, y, parts[part].w, parts[part].h * stretch_y, rfNearest) + else + if (col = 1) then + StretchRect(parts[part].imgdata, 0, 0, parts[part].w, parts[part].h, + FImages[0], x, y, parts[part].w * stretch_x, parts[part].h, rfNearest) + else + CopyRect(parts[part].imgdata, 0, 0, parts[part].w, parts[part].h, + FImages[0], x, y ); + if row = 1 then + y := y + parts[part].h * stretch_y + else + y := y + parts[part].h; + end; + end; + if cols[col] > 0 then + begin + if (col = 1) then + x := x + parts[part].w * stretch_x + else + x := x + parts[part].w; end; end; - Self.FDataType := [DT_Decoded32]; -end; - - - - -function TOniImage.WriteToBMP(filename: String): Boolean; -var - filestream: TFileStream; -begin - filestream := TFileStream.Create(filename, fmCreate); - GetAsBMP(TStream(filestream)); - filestream.Free; -end; - - - -function TOniImage.GetMipMappedImage(var Target: TByteData): Boolean; -var - i: Integer; - x, y: Word; - fadelvldata: TByteData; - revert: Boolean; -begin - Result := False; - - // if not (DT_Decoded32 in Self.FDataType) then - // Self.DecodeImage; - if Self.FStoreType = 9 then - Self.DecompressImage; - if not (DT_OniReverted in Self.FDataType) then - begin - revert := True; - Self.RevertImage; - end - else - revert := False; + FreeImage(pspcimage); + for i := 0 to 8 do + if parts[i].used then + FreeImage(parts[i].imgdata); - x := Self.FWidth; - y := Self.FHeight; - SetLength(Target, x * y * Self.FDepth div 8); - SetLength(fadelvldata, x * y * Self.FDepth div 8); - for i := 0 to Length(Target) - 1 do - begin - Target[i] := Self.FData[i]; - fadelvldata[i] := Self.FData[i]; - end; - repeat - fadelvldata := Self.ResizeImage(x, y, fadelvldata); - x := x div 2; - y := y div 2; - SetLength(Target, Length(Target) + x * y * Self.FDepth div 8); - for i := 0 to Length(fadelvldata) - 1 do - Target[Length(Target) - x * y * Self.FDepth div 8 + i] := fadelvldata[i]; - until (x = 1) or (y = 1) or ((x mod 2) = 1) or ((y mod 2) = 1); - if (x > 1) and (y > 1) then - Exit; Result := True; - - if revert then - Self.RevertImage; -end; - - -function TOniImage.GetMipMappedImage(var Target: TStream): Boolean; -var - data: TByteData; - streampos: Integer; -begin - Result := GetMipMappedImage(data); - if not Assigned(Target) then - Target := TMemoryStream.Create; - streampos := Target.Position; - Target.Write(data[0], Length(data)); - Target.Seek(streampos, soFromBeginning); end; - end. \ No newline at end of file