| @@ -1004,6 +1004,7 @@ procedure glBitmapGetDefaultTextureWrap(var S, T, R: Cardinal); | |||||
| function glBitmapPosition(X: Integer = -1; Y: Integer = -1): TglBitmapPixelPosition; | function glBitmapPosition(X: Integer = -1; Y: Integer = -1): TglBitmapPixelPosition; | ||||
| function glBitmapColorRec(const r, g, b, a: Cardinal): TglBitmapColorRec; | function glBitmapColorRec(const r, g, b, a: Cardinal): TglBitmapColorRec; | ||||
| function glBitmapColorRecCmp(const r1, r2: TglBitmapColorRec): Boolean; | |||||
| var | var | ||||
| glBitmapDefaultDeleteTextureOnFree: Boolean; | glBitmapDefaultDeleteTextureOnFree: Boolean; | ||||
| @@ -1052,6 +1053,7 @@ type | |||||
| fFormat: TglBitmapFormat; | fFormat: TglBitmapFormat; | ||||
| fWithAlpha: TglBitmapFormat; | fWithAlpha: TglBitmapFormat; | ||||
| fWithoutAlpha: TglBitmapFormat; | fWithoutAlpha: TglBitmapFormat; | ||||
| fRGBInverted: TglBitmapFormat; | |||||
| fPixelSize: Single; | fPixelSize: Single; | ||||
| fRange: TglBitmapColorRec; | fRange: TglBitmapColorRec; | ||||
| @@ -1066,6 +1068,7 @@ type | |||||
| property Format: TglBitmapFormat read fFormat; | property Format: TglBitmapFormat read fFormat; | ||||
| property WithAlpha: TglBitmapFormat read fWithAlpha; | property WithAlpha: TglBitmapFormat read fWithAlpha; | ||||
| property WithoutAlpha: TglBitmapFormat read fWithoutAlpha; | property WithoutAlpha: TglBitmapFormat read fWithoutAlpha; | ||||
| property RGBInverted: TglBitmapFormat read fRGBInverted; | |||||
| property Components: Integer read GetComponents; | property Components: Integer read GetComponents; | ||||
| property PixelSize: Single read fPixelSize; | property PixelSize: Single read fPixelSize; | ||||
| @@ -1553,6 +1556,18 @@ begin | |||||
| result.a := a; | result.a := a; | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function glBitmapColorRecCmp(const r1, r2: TglBitmapColorRec): Boolean; | |||||
| var | |||||
| i: Integer; | |||||
| begin | |||||
| result := false; | |||||
| for i := 0 to high(r1.arr) do | |||||
| if (r1.arr[i] <> r2.arr[i]) then | |||||
| exit; | |||||
| result := true; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function glBitmapShiftRec(const r, g, b, a: Byte): TShiftRec; | function glBitmapShiftRec(const r, g, b, a: Byte): TShiftRec; | ||||
| begin | begin | ||||
| @@ -1565,7 +1580,7 @@ end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function FormatGetSupportedFiles(const aFormat: TglBitmapFormat): TglBitmapFileTypes; | function FormatGetSupportedFiles(const aFormat: TglBitmapFormat): TglBitmapFileTypes; | ||||
| begin | begin | ||||
| result := [ftDDS, ftTGA]; | |||||
| result := [ftDDS]; | |||||
| if (aFormat in [ | if (aFormat in [ | ||||
| //4 bbp | //4 bbp | ||||
| @@ -1586,6 +1601,22 @@ begin | |||||
| tfBGR10, tfBGR10A2, tfBGRA8]) then | tfBGR10, tfBGR10A2, tfBGRA8]) then | ||||
| result := result + [ftBMP]; | result := result + [ftBMP]; | ||||
| if (aFormat in [ | |||||
| //8 bpp | |||||
| tfLuminance8, tfAlpha8, | |||||
| //16 bpp | |||||
| tfLuminance16, tfLuminance8Alpha8, | |||||
| tfRGB5, tfRGB5A1, tfRGBA4, | |||||
| tfBGR5, tfBGR5A1, tfBGRA4, | |||||
| //24 bpp | |||||
| tfRGB8, tfBGR8, | |||||
| //32 bpp | |||||
| tfRGB10A2, tfRGBA8, tfBGR10A2, tfBGRA8]) then | |||||
| result := result + [ftTGA]; | |||||
| //TODO Supported File Formats! | //TODO Supported File Formats! | ||||
| (* | (* | ||||
| @@ -2204,6 +2235,7 @@ begin | |||||
| fFormat := tfEmpty; | fFormat := tfEmpty; | ||||
| fWithAlpha := tfEmpty; | fWithAlpha := tfEmpty; | ||||
| fWithoutAlpha := tfEmpty; | fWithoutAlpha := tfEmpty; | ||||
| fRGBInverted := tfEmpty; | |||||
| fPixelSize := 0.0; | fPixelSize := 0.0; | ||||
| fglFormat := 0; | fglFormat := 0; | ||||
| @@ -2932,6 +2964,7 @@ begin | |||||
| fFormat := tfRGB4; | fFormat := tfRGB4; | ||||
| fWithAlpha := tfRGBA4; | fWithAlpha := tfRGBA4; | ||||
| fWithoutAlpha := tfRGB4; | fWithoutAlpha := tfRGB4; | ||||
| fRGBInverted := tfBGR4; | |||||
| fRange.r := $F; | fRange.r := $F; | ||||
| fRange.g := $F; | fRange.g := $F; | ||||
| fRange.b := $F; | fRange.b := $F; | ||||
| @@ -2949,6 +2982,7 @@ begin | |||||
| fFormat := tfR5G6B5; | fFormat := tfR5G6B5; | ||||
| fWithAlpha := tfRGBA4; | fWithAlpha := tfRGBA4; | ||||
| fWithoutAlpha := tfR5G6B5; | fWithoutAlpha := tfR5G6B5; | ||||
| fRGBInverted := tfB5G6R5; | |||||
| fRange.r := $1F; | fRange.r := $1F; | ||||
| fRange.g := $3F; | fRange.g := $3F; | ||||
| fRange.b := $1F; | fRange.b := $1F; | ||||
| @@ -2966,6 +3000,7 @@ begin | |||||
| fFormat := tfRGB5; | fFormat := tfRGB5; | ||||
| fWithAlpha := tfRGB5A1; | fWithAlpha := tfRGB5A1; | ||||
| fWithoutAlpha := tfRGB5; | fWithoutAlpha := tfRGB5; | ||||
| fRGBInverted := tfBGR5; | |||||
| fRange.r := $1F; | fRange.r := $1F; | ||||
| fRange.g := $1F; | fRange.g := $1F; | ||||
| fRange.b := $1F; | fRange.b := $1F; | ||||
| @@ -2983,6 +3018,7 @@ begin | |||||
| fFormat := tfRGB8; | fFormat := tfRGB8; | ||||
| fWithAlpha := tfRGBA8; | fWithAlpha := tfRGBA8; | ||||
| fWithoutAlpha := tfRGB8; | fWithoutAlpha := tfRGB8; | ||||
| fRGBInverted := tfBGR8; | |||||
| fglInternalFormat := GL_RGB8; | fglInternalFormat := GL_RGB8; | ||||
| end; | end; | ||||
| @@ -2992,6 +3028,7 @@ begin | |||||
| fFormat := tfRGB10; | fFormat := tfRGB10; | ||||
| fWithAlpha := tfRGB10A2; | fWithAlpha := tfRGB10A2; | ||||
| fWithoutAlpha := tfRGB10; | fWithoutAlpha := tfRGB10; | ||||
| fRGBInverted := tfBGR10; | |||||
| fRange.r := $3FF; | fRange.r := $3FF; | ||||
| fRange.g := $3FF; | fRange.g := $3FF; | ||||
| fRange.b := $3FF; | fRange.b := $3FF; | ||||
| @@ -3009,6 +3046,7 @@ begin | |||||
| fFormat := tfRGB12; | fFormat := tfRGB12; | ||||
| fWithAlpha := tfRGBA12; | fWithAlpha := tfRGBA12; | ||||
| fWithoutAlpha := tfRGB12; | fWithoutAlpha := tfRGB12; | ||||
| fRGBInverted := tfBGR12; | |||||
| fglInternalFormat := GL_RGB12; | fglInternalFormat := GL_RGB12; | ||||
| end; | end; | ||||
| @@ -3018,6 +3056,7 @@ begin | |||||
| fFormat := tfRGB16; | fFormat := tfRGB16; | ||||
| fWithAlpha := tfRGBA16; | fWithAlpha := tfRGBA16; | ||||
| fWithoutAlpha := tfRGB16; | fWithoutAlpha := tfRGB16; | ||||
| fRGBInverted := tfBGR16; | |||||
| fglInternalFormat := GL_RGB16; | fglInternalFormat := GL_RGB16; | ||||
| end; | end; | ||||
| @@ -3027,6 +3066,7 @@ begin | |||||
| fFormat := tfRGBA2; | fFormat := tfRGBA2; | ||||
| fWithAlpha := tfRGBA2; | fWithAlpha := tfRGBA2; | ||||
| fWithoutAlpha := tfR3G3B2; | fWithoutAlpha := tfR3G3B2; | ||||
| fRGBInverted := tfBGRA2; | |||||
| fglInternalFormat := GL_RGBA2; | fglInternalFormat := GL_RGBA2; | ||||
| end; | end; | ||||
| @@ -3036,6 +3076,7 @@ begin | |||||
| fFormat := tfRGBA4; | fFormat := tfRGBA4; | ||||
| fWithAlpha := tfRGBA4; | fWithAlpha := tfRGBA4; | ||||
| fWithoutAlpha := tfRGB4; | fWithoutAlpha := tfRGB4; | ||||
| fRGBInverted := tfBGRA4; | |||||
| fRange.r := $F; | fRange.r := $F; | ||||
| fRange.g := $F; | fRange.g := $F; | ||||
| fRange.b := $F; | fRange.b := $F; | ||||
| @@ -3055,6 +3096,7 @@ begin | |||||
| fFormat := tfRGB5A1; | fFormat := tfRGB5A1; | ||||
| fWithAlpha := tfRGB5A1; | fWithAlpha := tfRGB5A1; | ||||
| fWithoutAlpha := tfRGB5; | fWithoutAlpha := tfRGB5; | ||||
| fRGBInverted := tfBGR5A1; | |||||
| fRange.r := $1F; | fRange.r := $1F; | ||||
| fRange.g := $1F; | fRange.g := $1F; | ||||
| fRange.b := $1F; | fRange.b := $1F; | ||||
| @@ -3074,6 +3116,7 @@ begin | |||||
| fFormat := tfRGBA8; | fFormat := tfRGBA8; | ||||
| fWithAlpha := tfRGBA8; | fWithAlpha := tfRGBA8; | ||||
| fWithoutAlpha := tfRGB8; | fWithoutAlpha := tfRGB8; | ||||
| fRGBInverted := tfBGRA8; | |||||
| fglInternalFormat := GL_RGBA8; | fglInternalFormat := GL_RGBA8; | ||||
| end; | end; | ||||
| @@ -3083,6 +3126,7 @@ begin | |||||
| fFormat := tfRGB10A2; | fFormat := tfRGB10A2; | ||||
| fWithAlpha := tfRGB10A2; | fWithAlpha := tfRGB10A2; | ||||
| fWithoutAlpha := tfRGB10; | fWithoutAlpha := tfRGB10; | ||||
| fRGBInverted := tfBGR10A2; | |||||
| fRange.r := $3FF; | fRange.r := $3FF; | ||||
| fRange.g := $3FF; | fRange.g := $3FF; | ||||
| fRange.b := $3FF; | fRange.b := $3FF; | ||||
| @@ -3102,6 +3146,7 @@ begin | |||||
| fFormat := tfRGBA12; | fFormat := tfRGBA12; | ||||
| fWithAlpha := tfRGBA12; | fWithAlpha := tfRGBA12; | ||||
| fWithoutAlpha := tfRGB12; | fWithoutAlpha := tfRGB12; | ||||
| fRGBInverted := tfBGRA12; | |||||
| fglInternalFormat := GL_RGBA12; | fglInternalFormat := GL_RGBA12; | ||||
| end; | end; | ||||
| @@ -3111,6 +3156,7 @@ begin | |||||
| fFormat := tfRGBA16; | fFormat := tfRGBA16; | ||||
| fWithAlpha := tfRGBA16; | fWithAlpha := tfRGBA16; | ||||
| fWithoutAlpha := tfRGB16; | fWithoutAlpha := tfRGB16; | ||||
| fRGBInverted := tfBGRA16; | |||||
| fglInternalFormat := GL_RGBA16; | fglInternalFormat := GL_RGBA16; | ||||
| end; | end; | ||||
| @@ -3121,6 +3167,7 @@ begin | |||||
| fFormat := tfBGR4; | fFormat := tfBGR4; | ||||
| fWithAlpha := tfBGRA4; | fWithAlpha := tfBGRA4; | ||||
| fWithoutAlpha := tfBGR4; | fWithoutAlpha := tfBGR4; | ||||
| fRGBInverted := tfRGB4; | |||||
| fRange.r := $F; | fRange.r := $F; | ||||
| fRange.g := $F; | fRange.g := $F; | ||||
| fRange.b := $F; | fRange.b := $F; | ||||
| @@ -3143,6 +3190,7 @@ begin | |||||
| fFormat := tfB5G6R5; | fFormat := tfB5G6R5; | ||||
| fWithAlpha := tfBGRA4; | fWithAlpha := tfBGRA4; | ||||
| fWithoutAlpha := tfB5G6R5; | fWithoutAlpha := tfB5G6R5; | ||||
| fRGBInverted := tfR5G6B5; | |||||
| fRange.r := $1F; | fRange.r := $1F; | ||||
| fRange.g := $3F; | fRange.g := $3F; | ||||
| fRange.b := $1F; | fRange.b := $1F; | ||||
| @@ -3154,9 +3202,6 @@ begin | |||||
| fglDataFormat := GL_UNSIGNED_SHORT_5_6_5; | fglDataFormat := GL_UNSIGNED_SHORT_5_6_5; | ||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| constructor TfdBGR5.Create; | constructor TfdBGR5.Create; | ||||
| begin | begin | ||||
| inherited Create; | inherited Create; | ||||
| @@ -3164,6 +3209,7 @@ begin | |||||
| fFormat := tfBGR5; | fFormat := tfBGR5; | ||||
| fWithAlpha := tfBGR5A1; | fWithAlpha := tfBGR5A1; | ||||
| fWithoutAlpha := tfBGR5; | fWithoutAlpha := tfBGR5; | ||||
| fRGBInverted := tfRGB5; | |||||
| fRange.r := $1F; | fRange.r := $1F; | ||||
| fRange.g := $1F; | fRange.g := $1F; | ||||
| fRange.b := $1F; | fRange.b := $1F; | ||||
| @@ -3183,6 +3229,7 @@ begin | |||||
| fFormat := tfBGR8; | fFormat := tfBGR8; | ||||
| fWithAlpha := tfBGRA8; | fWithAlpha := tfBGRA8; | ||||
| fWithoutAlpha := tfBGR8; | fWithoutAlpha := tfBGR8; | ||||
| fRGBInverted := tfRGB8; | |||||
| fglInternalFormat := GL_RGB8; | fglInternalFormat := GL_RGB8; | ||||
| end; | end; | ||||
| @@ -3192,6 +3239,7 @@ begin | |||||
| fFormat := tfBGR10; | fFormat := tfBGR10; | ||||
| fWithAlpha := tfBGR10A2; | fWithAlpha := tfBGR10A2; | ||||
| fWithoutAlpha := tfBGR10; | fWithoutAlpha := tfBGR10; | ||||
| fRGBInverted := tfRGB10; | |||||
| fRange.r := $3FF; | fRange.r := $3FF; | ||||
| fRange.g := $3FF; | fRange.g := $3FF; | ||||
| fRange.b := $3FF; | fRange.b := $3FF; | ||||
| @@ -3211,6 +3259,7 @@ begin | |||||
| fFormat := tfBGR12; | fFormat := tfBGR12; | ||||
| fWithAlpha := tfBGRA12; | fWithAlpha := tfBGRA12; | ||||
| fWithoutAlpha := tfBGR12; | fWithoutAlpha := tfBGR12; | ||||
| fRGBInverted := tfRGB12; | |||||
| fglInternalFormat := GL_RGB12; | fglInternalFormat := GL_RGB12; | ||||
| end; | end; | ||||
| @@ -3220,6 +3269,7 @@ begin | |||||
| fFormat := tfBGR16; | fFormat := tfBGR16; | ||||
| fWithAlpha := tfBGRA16; | fWithAlpha := tfBGRA16; | ||||
| fWithoutAlpha := tfBGR16; | fWithoutAlpha := tfBGR16; | ||||
| fRGBInverted := tfRGB16; | |||||
| fglInternalFormat := GL_RGB16; | fglInternalFormat := GL_RGB16; | ||||
| end; | end; | ||||
| @@ -3229,6 +3279,7 @@ begin | |||||
| fFormat := tfBGRA2; | fFormat := tfBGRA2; | ||||
| fWithAlpha := tfBGRA4; | fWithAlpha := tfBGRA4; | ||||
| fWithoutAlpha := tfBGR4; | fWithoutAlpha := tfBGR4; | ||||
| fRGBInverted := tfRGBA2; | |||||
| fglInternalFormat := GL_RGBA2; | fglInternalFormat := GL_RGBA2; | ||||
| end; | end; | ||||
| @@ -3238,6 +3289,7 @@ begin | |||||
| fFormat := tfBGRA4; | fFormat := tfBGRA4; | ||||
| fWithAlpha := tfBGRA4; | fWithAlpha := tfBGRA4; | ||||
| fWithoutAlpha := tfBGR4; | fWithoutAlpha := tfBGR4; | ||||
| fRGBInverted := tfRGBA4; | |||||
| fRange.r := $F; | fRange.r := $F; | ||||
| fRange.g := $F; | fRange.g := $F; | ||||
| fRange.b := $F; | fRange.b := $F; | ||||
| @@ -3257,6 +3309,7 @@ begin | |||||
| fFormat := tfBGR5A1; | fFormat := tfBGR5A1; | ||||
| fWithAlpha := tfBGR5A1; | fWithAlpha := tfBGR5A1; | ||||
| fWithoutAlpha := tfBGR5; | fWithoutAlpha := tfBGR5; | ||||
| fRGBInverted := tfRGB5A1; | |||||
| fRange.r := $1F; | fRange.r := $1F; | ||||
| fRange.g := $1F; | fRange.g := $1F; | ||||
| fRange.b := $1F; | fRange.b := $1F; | ||||
| @@ -3276,6 +3329,7 @@ begin | |||||
| fFormat := tfBGRA8; | fFormat := tfBGRA8; | ||||
| fWithAlpha := tfBGRA8; | fWithAlpha := tfBGRA8; | ||||
| fWithoutAlpha := tfBGR8; | fWithoutAlpha := tfBGR8; | ||||
| fRGBInverted := tfRGBA8; | |||||
| fglInternalFormat := GL_RGBA8; | fglInternalFormat := GL_RGBA8; | ||||
| end; | end; | ||||
| @@ -3285,6 +3339,7 @@ begin | |||||
| fFormat := tfBGR10A2; | fFormat := tfBGR10A2; | ||||
| fWithAlpha := tfBGR10A2; | fWithAlpha := tfBGR10A2; | ||||
| fWithoutAlpha := tfBGR10; | fWithoutAlpha := tfBGR10; | ||||
| fRGBInverted := tfRGB10A2; | |||||
| fRange.r := $3FF; | fRange.r := $3FF; | ||||
| fRange.g := $3FF; | fRange.g := $3FF; | ||||
| fRange.b := $3FF; | fRange.b := $3FF; | ||||
| @@ -3304,6 +3359,7 @@ begin | |||||
| fFormat := tfBGRA12; | fFormat := tfBGRA12; | ||||
| fWithAlpha := tfBGRA12; | fWithAlpha := tfBGRA12; | ||||
| fWithoutAlpha := tfBGR12; | fWithoutAlpha := tfBGR12; | ||||
| fRGBInverted := tfRGBA12; | |||||
| fglInternalFormat := GL_RGBA12; | fglInternalFormat := GL_RGBA12; | ||||
| end; | end; | ||||
| @@ -3313,6 +3369,7 @@ begin | |||||
| fFormat := tfBGRA16; | fFormat := tfBGRA16; | ||||
| fWithAlpha := tfBGRA16; | fWithAlpha := tfBGRA16; | ||||
| fWithoutAlpha := tfBGR16; | fWithoutAlpha := tfBGR16; | ||||
| fRGBInverted := tfRGBA16; | |||||
| fglInternalFormat := GL_RGBA16; | fglInternalFormat := GL_RGBA16; | ||||
| end; | end; | ||||
| @@ -3531,9 +3588,6 @@ begin | |||||
| fColorTable[i].g := Round(((i shr Shift.g) and Range.g) / Range.g * 255); | fColorTable[i].g := Round(((i shr Shift.g) and Range.g) / Range.g * 255); | ||||
| fColorTable[i].b := Round(((i shr Shift.b) and Range.b) / Range.b * 255); | fColorTable[i].b := Round(((i shr Shift.b) and Range.b) / Range.b * 255); | ||||
| fColorTable[i].a := 0; | fColorTable[i].a := 0; | ||||
| s := SysUtils.Format('%.2X%.2X%.2X' + sLineBreak, [fColorTable[i].r, fColorTable[i].g, fColorTable[i].b]); | |||||
| fs.Write(s[1], Length(s)); | |||||
| end; | end; | ||||
| end; | end; | ||||
| end; | end; | ||||
| @@ -4004,6 +4058,8 @@ procedure TglBitmap.LoadFromFile(const aFilename: String); | |||||
| var | var | ||||
| fs: TFileStream; | fs: TFileStream; | ||||
| begin | begin | ||||
| if not FileExists(aFilename) then | |||||
| raise EglBitmapException.Create('file does not exist: ' + aFilename); | |||||
| fFilename := aFilename; | fFilename := aFilename; | ||||
| fs := TFileStream.Create(fFilename, fmOpenRead); | fs := TFileStream.Create(fFilename, fmOpenRead); | ||||
| try | try | ||||
| @@ -6422,29 +6478,43 @@ type | |||||
| ImageID: Byte; | ImageID: Byte; | ||||
| ColorMapType: Byte; | ColorMapType: Byte; | ||||
| ImageType: Byte; | ImageType: Byte; | ||||
| ColorMapSpec: Array[0..4] of Byte; | |||||
| //ColorMapSpec: Array[0..4] of Byte; | |||||
| ColorMapStart: Word; | |||||
| ColorMapLength: Word; | |||||
| ColorMapEntrySize: Byte; | |||||
| OrigX: Word; | OrigX: Word; | ||||
| OrigY: Word; | OrigY: Word; | ||||
| Width: Word; | Width: Word; | ||||
| Height: Word; | Height: Word; | ||||
| Bpp: Byte; | Bpp: Byte; | ||||
| ImageDes: Byte; | |||||
| ImageDesc: Byte; | |||||
| end; | end; | ||||
| const | const | ||||
| TGA_UNCOMPRESSED_RGB = 2; | |||||
| TGA_UNCOMPRESSED_GRAY = 3; | |||||
| TGA_COMPRESSED_RGB = 10; | |||||
| TGA_COMPRESSED_GRAY = 11; | |||||
| TGA_UNCOMPRESSED_COLOR_TABLE = 1; | |||||
| TGA_UNCOMPRESSED_RGB = 2; | |||||
| TGA_UNCOMPRESSED_GRAY = 3; | |||||
| TGA_COMPRESSED_COLOR_TABLE = 9; | |||||
| TGA_COMPRESSED_RGB = 10; | |||||
| TGA_COMPRESSED_GRAY = 11; | |||||
| TGA_NONE_COLOR_TABLE = 0; | |||||
| TGA_COLOR_TABLE = 1; | |||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TglBitmap.LoadTGA(const aStream: TStream): Boolean; | function TglBitmap.LoadTGA(const aStream: TStream): Boolean; | ||||
| var | var | ||||
| Header: TTGAHeader; | Header: TTGAHeader; | ||||
| NewImage, pData: PByte; | |||||
| StreamPos: Int64; | |||||
| PixelSize, LineSize, YStart, YEnd, YInc: Integer; | |||||
| Format: TglBitmapFormat; | |||||
| ImageData: PByte; | |||||
| StartPosition: Int64; | |||||
| PixelSize, LineSize: Integer; | |||||
| tgaFormat: TglBitmapFormat; | |||||
| FormatDesc: TFormatDescriptor; | |||||
| Counter: packed record | |||||
| X, Y: packed record | |||||
| low, high, dir: Integer; | |||||
| end; | |||||
| end; | |||||
| const | const | ||||
| CACHE_SIZE = $4000; | CACHE_SIZE = $4000; | ||||
| @@ -6452,195 +6522,233 @@ const | |||||
| //////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure ReadUncompressed; | procedure ReadUncompressed; | ||||
| var | var | ||||
| RowSize: Integer; | |||||
| i, j: Integer; | |||||
| buf, tmp1, tmp2: PByte; | |||||
| begin | begin | ||||
| RowSize := Header.Width * PixelSize; | |||||
| // copy line by line | |||||
| while YStart <> YEnd + YInc do begin | |||||
| pData := NewImage; | |||||
| Inc(pData, YStart * LineSize); | |||||
| aStream.Read(pData^, RowSize); | |||||
| Inc(YStart, YInc); | |||||
| buf := nil; | |||||
| if (Counter.X.dir < 0) then | |||||
| buf := GetMem(LineSize); | |||||
| try | |||||
| while (Counter.Y.low <> Counter.Y.high + counter.Y.dir) do begin | |||||
| tmp1 := ImageData + (Counter.Y.low * LineSize); //pointer to LineStart | |||||
| if (Counter.X.dir < 0) then begin //flip X | |||||
| aStream.Read(buf^, LineSize); | |||||
| tmp2 := buf + LineSize - PixelSize; //pointer to last pixel in line | |||||
| for i := 0 to Header.Width-1 do begin //for all pixels in line | |||||
| for j := 0 to PixelSize-1 do begin //for all bytes in pixel | |||||
| tmp1^ := tmp2^; | |||||
| inc(tmp1); | |||||
| inc(tmp2); | |||||
| end; | |||||
| dec(tmp2, 2*PixelSize); //move 2 backwards, because j-loop moved 1 forward | |||||
| end; | |||||
| end else | |||||
| aStream.Read(tmp1^, LineSize); | |||||
| inc(Counter.Y.low, Counter.Y.dir); //move to next line index | |||||
| end; | |||||
| finally | |||||
| if Assigned(buf) then | |||||
| FreeMem(buf); | |||||
| end; | end; | ||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure ReadCompressed; | procedure ReadCompressed; | ||||
| var | |||||
| HeaderWidth, HeaderHeight: Integer; | |||||
| LinePixelsRead, ImgPixelsRead, ImgPixelsToRead: Integer; | |||||
| Cache: PByte; | |||||
| CacheSize, CachePos: Integer; | |||||
| Temp: Byte; | |||||
| TempBuf: Array [0..15] of Byte; | |||||
| PixelRepeat: Boolean; | |||||
| PixelToRead, TempPixels: Integer; | |||||
| ///////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////// | ||||
| var | |||||
| TmpData: PByte; | |||||
| LinePixelsRead: Integer; | |||||
| procedure CheckLine; | procedure CheckLine; | ||||
| begin | begin | ||||
| if LinePixelsRead >= HeaderWidth then begin | |||||
| if (LinePixelsRead >= Header.Width) then begin | |||||
| LinePixelsRead := 0; | LinePixelsRead := 0; | ||||
| pData := NewImage; | |||||
| Inc(YStart, YInc); | |||||
| Inc(pData, YStart * LineSize); | |||||
| inc(Counter.Y.low, Counter.Y.dir); //next line index | |||||
| TmpData := ImageData + Counter.Y.low * LineSize; //set line | |||||
| if (Counter.X.dir < 0) then //if x flipped then | |||||
| TmpData := TmpData + LineSize - PixelSize; //set last pixel | |||||
| end; | end; | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////// | ||||
| var | |||||
| Cache: PByte; | |||||
| CacheSize, CachePos: Integer; | |||||
| procedure CachedRead(out Buffer; Count: Integer); | procedure CachedRead(out Buffer; Count: Integer); | ||||
| var | var | ||||
| BytesRead: Integer; | BytesRead: Integer; | ||||
| begin | begin | ||||
| if (CachePos + Count) > CacheSize then begin | |||||
| if (CachePos + Count > CacheSize) then begin | |||||
| //if buffer overflow save non read bytes | |||||
| BytesRead := 0; | BytesRead := 0; | ||||
| // Read Data | |||||
| if CacheSize - CachePos > 0 then begin | |||||
| if (CacheSize - CachePos > 0) then begin | |||||
| BytesRead := CacheSize - CachePos; | BytesRead := CacheSize - CachePos; | ||||
| Move(pByteArray(Cache)^[CachePos], Buffer, BytesRead); | |||||
| Inc(CachePos, BytesRead); | |||||
| Move(PByteArray(Cache)^[CachePos], Buffer, BytesRead); | |||||
| inc(CachePos, BytesRead); | |||||
| end; | end; | ||||
| // Reload Data | |||||
| //load cache from file | |||||
| CacheSize := Min(CACHE_SIZE, aStream.Size - aStream.Position); | CacheSize := Min(CACHE_SIZE, aStream.Size - aStream.Position); | ||||
| aStream.Read(Cache^, CacheSize); | aStream.Read(Cache^, CacheSize); | ||||
| CachePos := 0; | CachePos := 0; | ||||
| // Read else | |||||
| if Count - BytesRead > 0 then begin | |||||
| Move(pByteArray(Cache)^[CachePos], TByteArray(Buffer)[BytesRead], Count - BytesRead); | |||||
| Inc(CachePos, Count - BytesRead); | |||||
| //read rest of requested bytes | |||||
| if (Count - BytesRead > 0) then begin | |||||
| Move(PByteArray(Cache)^[CachePos], TByteArray(Buffer)[BytesRead], Count - BytesRead); | |||||
| inc(CachePos, Count - BytesRead); | |||||
| end; | end; | ||||
| end else begin | end else begin | ||||
| Move(pByteArray(Cache)^[CachePos], Buffer, Count); | |||||
| Inc(CachePos, Count); | |||||
| //if no buffer overflow just read the data | |||||
| Move(PByteArray(Cache)^[CachePos], Buffer, Count); | |||||
| inc(CachePos, Count); | |||||
| end; | |||||
| end; | |||||
| procedure PixelToBuffer(const aData: PByte; var aBuffer: PByte); | |||||
| begin | |||||
| case PixelSize of | |||||
| 1: begin | |||||
| aBuffer^ := aData^; | |||||
| inc(aBuffer, Counter.X.dir); | |||||
| end; | |||||
| 2: begin | |||||
| PWord(aBuffer)^ := PWord(aData)^; | |||||
| inc(aBuffer, 2 * Counter.X.dir); | |||||
| end; | |||||
| 3: begin | |||||
| PByteArray(aBuffer)^[0] := PByteArray(aData)^[0]; | |||||
| PByteArray(aBuffer)^[1] := PByteArray(aData)^[1]; | |||||
| PByteArray(aBuffer)^[2] := PByteArray(aData)^[2]; | |||||
| inc(aBuffer, 3 * Counter.X.dir); | |||||
| end; | |||||
| 4: begin | |||||
| PCardinal(aBuffer)^ := PCardinal(aData)^; | |||||
| inc(aBuffer, 4 * Counter.X.dir); | |||||
| end; | |||||
| end; | end; | ||||
| end; | end; | ||||
| var | |||||
| TotalPixelsToRead, TotalPixelsRead: Integer; | |||||
| Temp: Byte; | |||||
| buf: array [0..3] of Byte; //1 pixel is max 32bit long | |||||
| PixelRepeat: Boolean; | |||||
| PixelsToRead, PixelCount: Integer; | |||||
| begin | begin | ||||
| CacheSize := 0; | CacheSize := 0; | ||||
| CachePos := 0; | |||||
| CachePos := 0; | |||||
| HeaderWidth := Header.Width; | |||||
| HeaderHeight := Header.Height; | |||||
| TotalPixelsToRead := Header.Width * Header.Height; | |||||
| TotalPixelsRead := 0; | |||||
| LinePixelsRead := 0; | |||||
| GetMem(Cache, CACHE_SIZE); // 16K Buffer | |||||
| GetMem(Cache, CACHE_SIZE); | |||||
| try | try | ||||
| ImgPixelsToRead := HeaderWidth * HeaderHeight; | |||||
| ImgPixelsRead := 0; | |||||
| LinePixelsRead := 0; | |||||
| TmpData := ImageData + Counter.Y.low * LineSize; //set line | |||||
| if (Counter.X.dir < 0) then //if x flipped then | |||||
| TmpData := TmpData + LineSize - PixelSize; //set last pixel | |||||
| pData := NewImage; | |||||
| Inc(pData, YStart * LineSize); | |||||
| // Read until all Pixels | |||||
| repeat | repeat | ||||
| //read CommandByte | |||||
| CachedRead(Temp, 1); | CachedRead(Temp, 1); | ||||
| PixelRepeat := Temp and $80 > 0; | |||||
| PixelToRead := (Temp and $7F) + 1; | |||||
| Inc(ImgPixelsRead, PixelToRead); | |||||
| if PixelRepeat then begin | |||||
| // repeat one pixel x times | |||||
| CachedRead(TempBuf[0], PixelSize); | |||||
| // repeat Pixel | |||||
| while PixelToRead > 0 do begin | |||||
| CheckLine; | |||||
| TempPixels := HeaderWidth - LinePixelsRead; | |||||
| if PixelToRead < TempPixels then | |||||
| TempPixels := PixelToRead; | |||||
| Inc(LinePixelsRead, TempPixels); | |||||
| Dec(PixelToRead, TempPixels); | |||||
| while TempPixels > 0 do begin | |||||
| case PixelSize of | |||||
| 1: begin | |||||
| pData^ := TempBuf[0]; | |||||
| Inc(pData); | |||||
| end; | |||||
| 2: begin | |||||
| pWord(pData)^ := pWord(@TempBuf[0])^; | |||||
| Inc(pData, 2); | |||||
| end; | |||||
| 3: begin | |||||
| pWord(pData)^ := pWord(@TempBuf[0])^; | |||||
| Inc(pData, 2); | |||||
| pData^ := TempBuf[2]; | |||||
| Inc(pData); | |||||
| end; | |||||
| 4: begin | |||||
| pDWord(pData)^ := pDWord(@TempBuf[0])^; | |||||
| Inc(pData, 4); | |||||
| end; | |||||
| end; | |||||
| Dec(TempPixels); | |||||
| end; | |||||
| end; | |||||
| end else begin | |||||
| // copy x pixels | |||||
| while PixelToRead > 0 do begin | |||||
| CheckLine; | |||||
| TempPixels := HeaderWidth - LinePixelsRead; | |||||
| if PixelToRead < TempPixels then | |||||
| TempPixels := PixelToRead; | |||||
| CachedRead(pData^, PixelSize * TempPixels); | |||||
| Inc(pData, PixelSize * TempPixels); | |||||
| Inc(LinePixelsRead, TempPixels); | |||||
| Dec(PixelToRead, TempPixels); | |||||
| PixelRepeat := (Temp and $80) > 0; | |||||
| PixelsToRead := (Temp and $7F) + 1; | |||||
| inc(TotalPixelsRead, PixelsToRead); | |||||
| if PixelRepeat then | |||||
| CachedRead(buf[0], PixelSize); | |||||
| while (PixelsToRead > 0) do begin | |||||
| CheckLine; | |||||
| PixelCount := Min(Header.Width - LinePixelsRead, PixelsToRead); //max read to EOL or EOF | |||||
| while (PixelCount > 0) do begin | |||||
| if not PixelRepeat then | |||||
| CachedRead(buf[0], PixelSize); | |||||
| PixelToBuffer(@buf[0], TmpData); | |||||
| inc(LinePixelsRead); | |||||
| dec(PixelsToRead); | |||||
| dec(PixelCount); | |||||
| end; | end; | ||||
| end; | end; | ||||
| until ImgPixelsRead >= ImgPixelsToRead; | |||||
| until (TotalPixelsRead >= TotalPixelsToRead); | |||||
| finally | finally | ||||
| FreeMem(Cache) | |||||
| FreeMem(Cache); | |||||
| end; | end; | ||||
| end; | end; | ||||
| function IsGrayFormat: Boolean; | |||||
| begin | |||||
| result := Header.ImageType in [TGA_UNCOMPRESSED_GRAY, TGA_COMPRESSED_GRAY]; | |||||
| end; | |||||
| begin | begin | ||||
| result := false; | result := false; | ||||
| // reading header to test file and set cursor back to begin | // reading header to test file and set cursor back to begin | ||||
| StreamPos := aStream.Position; | |||||
| StartPosition := aStream.Position; | |||||
| aStream.Read(Header, SizeOf(Header)); | aStream.Read(Header, SizeOf(Header)); | ||||
| // no colormapped files | // no colormapped files | ||||
| if (Header.ColorMapType = 0) then begin | |||||
| if Header.ImageType in [TGA_UNCOMPRESSED_RGB, TGA_UNCOMPRESSED_GRAY, TGA_COMPRESSED_RGB, TGA_COMPRESSED_GRAY] then begin | |||||
| if (Header.ColorMapType = TGA_NONE_COLOR_TABLE) and (Header.ImageType in [ | |||||
| TGA_UNCOMPRESSED_RGB, TGA_UNCOMPRESSED_GRAY, TGA_COMPRESSED_RGB, TGA_COMPRESSED_GRAY]) then | |||||
| begin | |||||
| try | |||||
| if Header.ImageID <> 0 then // skip image ID | |||||
| aStream.Position := aStream.Position + Header.ImageID; | |||||
| case Header.Bpp of | case Header.Bpp of | ||||
| //TODO 8: Format := tfAlpha8; | |||||
| 16: Format := tfLuminance8Alpha8; | |||||
| 24: Format := tfBGR8; | |||||
| 32: Format := tfBGRA8; | |||||
| else | |||||
| raise EglBitmapException.Create('LoadTga - unsupported BitsPerPixel found.'); | |||||
| 8: if IsGrayFormat then case (Header.ImageDesc and $F) of | |||||
| 0: tgaFormat := tfLuminance8; | |||||
| 8: tgaFormat := tfAlpha8; | |||||
| end; | |||||
| 16: if IsGrayFormat then case (Header.ImageDesc and $F) of | |||||
| 0: tgaFormat := tfLuminance16; | |||||
| 8: tgaFormat := tfLuminance8Alpha8; | |||||
| end else case (Header.ImageDesc and $F) of | |||||
| 0: tgaFormat := tfBGR5; | |||||
| 1: tgaFormat := tfBGR5A1; | |||||
| 4: tgaFormat := tfBGRA4; | |||||
| end; | |||||
| 24: if not IsGrayFormat then case (Header.ImageDesc and $F) of | |||||
| 0: tgaFormat := tfBGR8; | |||||
| end; | |||||
| 32: if not IsGrayFormat then case (Header.ImageDesc and $F) of | |||||
| 2: tgaFormat := tfBGR10A2; | |||||
| 8: tgaFormat := tfBGRA8; | |||||
| end; | |||||
| end; | end; | ||||
| // skip image ID | |||||
| if Header.ImageID <> 0 then | |||||
| aStream.Position := aStream.Position + Header.ImageID; | |||||
| if (tgaFormat = tfEmpty) then | |||||
| raise EglBitmapException.Create('LoadTga - unsupported format'); | |||||
| PixelSize := TFormatDescriptor.Get(Format).GetSize(1, 1); | |||||
| LineSize := Trunc(Header.Width * PixelSize); | |||||
| FormatDesc := TFormatDescriptor.Get(tgaFormat); | |||||
| PixelSize := FormatDesc.GetSize(1, 1); | |||||
| LineSize := FormatDesc.GetSize(Header.Width, 1); | |||||
| GetMem(NewImage, LineSize * Header.Height); | |||||
| GetMem(ImageData, LineSize * Header.Height); | |||||
| try | try | ||||
| //column direction | |||||
| if ((Header.ImageDesc and (1 shl 4)) > 0) then begin | |||||
| Counter.X.low := Header.Height-1;; | |||||
| Counter.X.high := 0; | |||||
| Counter.X.dir := -1; | |||||
| end else begin | |||||
| Counter.X.low := 0; | |||||
| Counter.X.high := Header.Height-1; | |||||
| Counter.X.dir := 1; | |||||
| end; | |||||
| // Row direction | // Row direction | ||||
| if (Header.ImageDes and $20 > 0) then begin | |||||
| YStart := 0; | |||||
| YEnd := Header.Height -1; | |||||
| YInc := 1; | |||||
| if ((Header.ImageDesc and (1 shl 5)) > 0) then begin | |||||
| Counter.Y.low := 0; | |||||
| Counter.Y.high := Header.Height-1; | |||||
| Counter.Y.dir := 1; | |||||
| end else begin | end else begin | ||||
| YStart := Header.Height -1; | |||||
| YEnd := 0; | |||||
| YInc := -1; | |||||
| Counter.Y.low := Header.Height-1;; | |||||
| Counter.Y.high := 0; | |||||
| Counter.Y.dir := -1; | |||||
| end; | end; | ||||
| // Read Image | // Read Image | ||||
| @@ -6651,97 +6759,106 @@ begin | |||||
| ReadCompressed; | ReadCompressed; | ||||
| end; | end; | ||||
| SetDataPointer(NewImage, Format, Header.Width, Header.Height); | |||||
| SetDataPointer(ImageData, tgaFormat, Header.Width, Header.Height); | |||||
| result := true; | result := true; | ||||
| except | except | ||||
| FreeMem(NewImage); | |||||
| FreeMem(ImageData); | |||||
| raise; | raise; | ||||
| end; | end; | ||||
| end | |||||
| else aStream.Position := StreamPos; | |||||
| finally | |||||
| aStream.Position := StartPosition; | |||||
| end; | |||||
| end | end | ||||
| else aStream.Position := StreamPos; | |||||
| else aStream.Position := StartPosition; | |||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TglBitmap.SaveTGA(const aStream: TStream); | procedure TglBitmap.SaveTGA(const aStream: TStream); | ||||
| var | var | ||||
| Header: TTGAHeader; | Header: TTGAHeader; | ||||
| Size: Integer; | |||||
| pTemp: pByte; | |||||
| LineSize, Size, x, y: Integer; | |||||
| Pixel: TglBitmapPixelData; | |||||
| LineBuf, SourceData, DestData: PByte; | |||||
| SourceMD, DestMD: Pointer; | |||||
| FormatDesc: TFormatDescriptor; | FormatDesc: TFormatDescriptor; | ||||
| procedure ConvertData(pTemp: pByte); | |||||
| var | |||||
| Idx, PixelSize: Integer; | |||||
| Temp: byte; | |||||
| begin | |||||
| PixelSize := fPixelSize; | |||||
| for Idx := 1 to Height * Width do begin | |||||
| Temp := pByteArray(pTemp)^[2]; | |||||
| pByteArray(pTemp)^[2] := pByteArray(pTemp)^[0]; | |||||
| pByteArray(pTemp)^[0] := Temp; | |||||
| Inc(pTemp, PixelSize); | |||||
| end; | |||||
| end; | |||||
| Converter: TFormatDescriptor; | |||||
| begin | begin | ||||
| if not (ftTGA in FormatGetSupportedFiles(Format)) then | if not (ftTGA in FormatGetSupportedFiles(Format)) then | ||||
| raise EglBitmapUnsupportedFormatFormat.Create('SaveTGA - ' + UNSUPPORTED_FORMAT); | raise EglBitmapUnsupportedFormatFormat.Create('SaveTGA - ' + UNSUPPORTED_FORMAT); | ||||
| //prepare header | |||||
| FillChar(Header, SizeOf(Header), 0); | FillChar(Header, SizeOf(Header), 0); | ||||
| case Format of | |||||
| //TODO ifAlpha8, ifLuminance8, ifDepth8: begin | |||||
| tfLuminance8: begin | |||||
| Header.ImageType := TGA_UNCOMPRESSED_GRAY; | |||||
| Header.Bpp := 8; | |||||
| end; | |||||
| tfLuminance8Alpha8: begin | |||||
| Header.ImageType := TGA_UNCOMPRESSED_GRAY; | |||||
| Header.Bpp := 16; | |||||
| end; | |||||
| tfRGB8, tfBGR8: begin | |||||
| Header.ImageType := TGA_UNCOMPRESSED_RGB; | |||||
| Header.Bpp := 24; | |||||
| end; | |||||
| tfRGBA8, tfBGRA8: begin | |||||
| Header.ImageType := TGA_UNCOMPRESSED_RGB; | |||||
| Header.Bpp := 32; | |||||
| end; | |||||
| else | |||||
| raise EglBitmapUnsupportedFormatFormat.Create('SaveTGA - ' + UNSUPPORTED_FORMAT); | |||||
| end; | |||||
| Header.Width := Width; | |||||
| Header.Height := Height; | |||||
| Header.ImageDes := $20; | |||||
| FormatDesc := TFormatDescriptor.Get(Format); | |||||
| //set ImageType | |||||
| if (Format in [tfLuminance8, tfLuminance6Alpha2, tfLuminance4Alpha4, tfAlpha8, | |||||
| tfLuminance16, tfLuminance12Alpha4, tfLuminance8Alpha8]) then | |||||
| Header.ImageType := TGA_UNCOMPRESSED_GRAY | |||||
| else | |||||
| Header.ImageType := TGA_UNCOMPRESSED_RGB; | |||||
| //set BitsPerPixel | |||||
| if (Format in [tfLuminance8, tfLuminance6Alpha2, tfLuminance4Alpha4, tfAlpha8]) then | |||||
| Header.Bpp := 8 | |||||
| else if (Format in [tfLuminance16, tfLuminance12Alpha4, tfLuminance8Alpha8, | |||||
| tfRGB5, tfBGR5, tfRGB5A1, tfBGR5A1, tfRGBA4, tfBGRA4]) then | |||||
| Header.Bpp := 16 | |||||
| else if (Format in [tfBGR8, tfRGB8]) then | |||||
| Header.Bpp := 24 | |||||
| else | |||||
| Header.Bpp := 32; | |||||
| if FormatDesc.HasAlpha then | |||||
| Header.ImageDes := Header.ImageDes or $08; | |||||
| //set AlphaBitCount | |||||
| case Format of | |||||
| tfRGB5A1, tfBGR5A1: | |||||
| Header.ImageDesc := 1 and $F; | |||||
| tfRGB10A2, tfBGR10A2: | |||||
| Header.ImageDesc := 2 and $F; | |||||
| tfRGBA4, tfBGRA4: | |||||
| Header.ImageDesc := 4 and $F; | |||||
| tfAlpha8, tfLuminance8Alpha8, tfRGBA8, tfBGRA8: | |||||
| Header.ImageDesc := 8 and $F; | |||||
| end; | |||||
| Header.Width := Width; | |||||
| Header.Height := Height; | |||||
| Header.ImageDesc := Header.ImageDesc or $20; //flip y | |||||
| aStream.Write(Header, SizeOf(Header)); | aStream.Write(Header, SizeOf(Header)); | ||||
| // convert RGB(A) to BGR(A) | // convert RGB(A) to BGR(A) | ||||
| Size := FormatDesc.GetSize(Dimension); | |||||
| if Format in [tfRGB8, tfRGBA8] then begin | |||||
| GetMem(pTemp, Size); | |||||
| end else | |||||
| pTemp := Data; | |||||
| try | |||||
| // convert data | |||||
| if Format in [tfRGB8, tfRGBA8] then begin | |||||
| Move(Data^, pTemp^, Size); | |||||
| ConvertData(pTemp); | |||||
| Converter := nil; | |||||
| FormatDesc := TFormatDescriptor.Get(Format); | |||||
| Size := FormatDesc.GetSize(Dimension); | |||||
| if Format in [tfRGB5, tfRGB5A1, tfRGBA4, tfRGB8, tfRGB10A2, tfRGBA8] then begin | |||||
| if (FormatDesc.RGBInverted = tfEmpty) then | |||||
| raise EglBitmapException.Create('inverted RGB format is empty'); | |||||
| Converter := TFormatDescriptor.Get(FormatDesc.RGBInverted); | |||||
| if not glBitmapColorRecCmp(Converter.Range, FormatDesc.Range) or | |||||
| (Converter.PixelSize <> FormatDesc.PixelSize) then | |||||
| raise EglBitmapException.Create('invalid inverted RGB format'); | |||||
| end; | |||||
| if Assigned(Converter) then begin | |||||
| LineSize := FormatDesc.GetSize(Width, 1); | |||||
| LineBuf := GetMem(LineSize); | |||||
| SourceMD := FormatDesc.CreateMappingData; | |||||
| DestMD := Converter.CreateMappingData; | |||||
| try | |||||
| SourceData := Data; | |||||
| for y := 0 to Height-1 do begin | |||||
| DestData := LineBuf; | |||||
| for x := 0 to Width-1 do begin | |||||
| FormatDesc.Unmap(SourceData, Pixel, SourceMD); | |||||
| Converter.Map(Pixel, DestData, DestMD); | |||||
| end; | |||||
| aStream.Write(LineBuf^, LineSize); | |||||
| end; | |||||
| finally | |||||
| FreeMem(LineBuf); | |||||
| FormatDesc.FreeMappingData(SourceMD); | |||||
| FormatDesc.FreeMappingData(DestMD); | |||||
| end; | end; | ||||
| // write data | |||||
| aStream.Write(pTemp^, Size); | |||||
| finally | |||||
| // free tempdata | |||||
| if Format in [tfRGB8, tfRGBA8] then | |||||
| FreeMem(pTemp); | |||||
| end; | |||||
| end else | |||||
| aStream.Write(Data^, Size); | |||||
| end; | end; | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||