123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit Formatx.TGA;
- (* Graphic engine friendly loading of TGA image *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
- GXS.ApplicationFileIO,
- Stage.Strings,
- GXS.Context,
- GXS.Graphics,
- Stage.TextureFormat;
- type
- TgxTGAImage = class(TgxBaseImage)
- public
- procedure LoadFromFile(const filename: string); override;
- procedure SaveToFile(const filename: string); override;
- procedure LoadFromStream(stream: TStream); override;
- procedure SaveToStream(stream: TStream); override;
- class function Capabilities: TDataFileCapabilities; override;
- procedure AssignFromTexture(textureContext: TgxContext;
- const textureHandle: GLuint;
- textureTarget: TglTextureTarget;
- const CurrentFormat: boolean;
- const intFormat: TglInternalFormat); reintroduce;
- end;
- //======================================================================
- implementation
- //======================================================================
- type
- TTGAFileHeader = packed record
- IDLength: Byte;
- ColorMapType: Byte;
- ImageType: Byte;
- ColorMapOrigin: Word;
- ColorMapLength: Word;
- ColorMapEntrySize: Byte;
- XOrigin: Word;
- YOrigin: Word;
- Width: Word;
- Height: Word;
- PixelSize: Byte;
- ImageDescriptor: Byte;
- end;
- procedure ReadAndUnPackRLETGA24(stream: TStream; destBuf: PAnsiChar;
- totalSize: Integer);
- type
- TRGB24 = packed record
- r, g, b: Byte;
- end;
- PRGB24 = ^TRGB24;
- var
- n: Integer;
- color: TRGB24;
- bufEnd: PAnsiChar;
- b: Byte;
- begin
- bufEnd := @destBuf[totalSize];
- while destBuf < bufEnd do
- begin
- stream.Read(b, 1);
- if b >= 128 then
- begin
- // repetition packet
- stream.Read(color, 3);
- b := (b and 127) + 1;
- while b > 0 do
- begin
- PRGB24(destBuf)^ := color;
- Inc(destBuf, 3);
- Dec(b);
- end;
- end
- else
- begin
- n := ((b and 127) + 1) * 3;
- stream.Read(destBuf^, n);
- Inc(destBuf, n);
- end;
- end;
- end;
- procedure ReadAndUnPackRLETGA32(stream: TStream; destBuf: PAnsiChar;
- totalSize: Integer);
- type
- TRGB32 = packed record
- r, g, b, a: Byte;
- end;
- PRGB32 = ^TRGB32;
- var
- n: Integer;
- color: TRGB32;
- bufEnd: PAnsiChar;
- b: Byte;
- begin
- bufEnd := @destBuf[totalSize];
- while destBuf < bufEnd do
- begin
- stream.Read(b, 1);
- if b >= 128 then
- begin
- // repetition packet
- stream.Read(color, 4);
- b := (b and 127) + 1;
- while b > 0 do
- begin
- PRGB32(destBuf)^ := color;
- Inc(destBuf, 4);
- Dec(b);
- end;
- end
- else
- begin
- n := ((b and 127) + 1) * 4;
- stream.Read(destBuf^, n);
- Inc(destBuf, n);
- end;
- end;
- end;
- procedure TgxTGAImage.LoadFromFile(const filename: string);
- var
- fs: TStream;
- begin
- if FileStreamExists(fileName) then
- begin
- fs := TFileStream.Create(fileName, fmOpenRead);
- try
- LoadFromStream(fs);
- finally
- fs.Free;
- ResourceName := filename;
- end;
- end
- else
- raise EInvalidRasterFile.CreateFmt('File %s not found', [filename]);
- end;
- procedure TgxTGAImage.SaveToFile(const filename: string);
- var
- fs: TStream;
- begin
- fs := TFileStream.Create(fileName, fmOpenWrite or fmCreate);
- try
- SaveToStream(fs);
- finally
- fs.Free;
- end;
- ResourceName := filename;
- end;
- // LoadFromStream
- //
- procedure TgxTGAImage.LoadFromStream(stream: TStream);
- var
- LHeader: TTGAFileHeader;
- y, rowSize, bufSize: Integer;
- verticalFlip: Boolean;
- unpackBuf: PAnsiChar;
- Ptr: PByte;
- begin
- stream.Read(LHeader, Sizeof(TTGAFileHeader));
- if LHeader.ColorMapType <> 0 then
- raise EInvalidRasterFile.Create('ColorMapped TGA unsupported');
- UnMipmap;
- FLOD[0].Width := LHeader.Width;
- FLOD[0].Height := LHeader.Height;
- FLOD[0].Depth := 0;
- case LHeader.PixelSize of
- 24:
- begin
- FColorFormat := GL_BGR;
- FInternalFormat := tfRGB8;
- FElementSize := 3;
- end;
- 32:
- begin
- FColorFormat := GL_RGBA;
- FInternalFormat := tfRGBA8;
- FElementSize := 4;
- end;
- else
- raise EInvalidRasterFile.Create('Unsupported TGA ImageType');
- end;
- FDataType := GL_UNSIGNED_BYTE;
- FCubeMap := False;
- FTextureArray := False;
- ReallocMem(FData, DataSize);
- rowSize := GetWidth * FElementSize;
- verticalFlip := ((LHeader.ImageDescriptor and $20) <> 1);
- if LHeader.IDLength > 0 then
- stream.Seek(LHeader.IDLength, soFromCurrent);
- case LHeader.ImageType of
- 2:
- begin // uncompressed RGB/RGBA
- if verticalFlip then
- begin
- Ptr := PByte(FData);
- Inc(Ptr, rowSize * (GetHeight - 1));
- for y := 0 to GetHeight - 1 do
- begin
- stream.Read(Ptr^, rowSize);
- Dec(Ptr, rowSize);
- end;
- end
- else
- stream.Read(FData^, rowSize * GetHeight);
- end;
- 10:
- begin // RLE encoded RGB/RGBA
- bufSize := GetHeight * rowSize;
- GetMem(unpackBuf, bufSize);
- try
- // read & unpack everything
- if LHeader.PixelSize = 24 then
- ReadAndUnPackRLETGA24(stream, unpackBuf, bufSize)
- else
- ReadAndUnPackRLETGA32(stream, unpackBuf, bufSize);
- // fillup bitmap
- if verticalFlip then
- begin
- Ptr := PByte(FData);
- Inc(Ptr, rowSize * (GetHeight - 1));
- for y := 0 to GetHeight - 1 do
- begin
- Move(unPackBuf[y * rowSize], Ptr^, rowSize);
- Dec(Ptr, rowSize);
- end;
- end
- else
- Move(unPackBuf[rowSize * GetHeight], FData^, rowSize * GetHeight);
- finally
- FreeMem(unpackBuf);
- end;
- end;
- else
- raise EInvalidRasterFile.CreateFmt('Unsupported TGA ImageType %d',
- [LHeader.ImageType]);
- end;
- end;
- procedure TgxTGAImage.SaveToStream(stream: TStream);
- begin
- {$MESSAGE Hint 'TgxTGAImage.SaveToStream not yet implemented' }
- end;
- procedure TgxTGAImage.AssignFromTexture(textureContext: TgxContext;
- const textureHandle: GLuint; textureTarget: TglTextureTarget;
- const CurrentFormat: boolean; const intFormat: TglInternalFormat);
- begin
- {$MESSAGE Hint 'TgxTGAImage.AssignFromTexture not yet implemented' }
- end;
- class function TgxTGAImage.Capabilities: TDataFileCapabilities;
- begin
- Result := [dfcRead {, dfcWrite}];
- end;
- //===========================================================
- initialization
- //===========================================================
- RegisterRasterFormat('tga', 'TARGA Image File', TgxTGAImage);
- end.
|