///////////////////////////////////////////////////////////////////////
// Copyright (C) Andru 2007                                          //
// mail: dr.andru@gmail.com                                          //
// site: http://andru.2x4.ru                                         //
//                                                                   //
// OMEGA Engine is free software.                                    //
//                                                                   //
// You may redistribute it and/or modify it under the terms of the   //
// GNU General Public License, as published by the Free Software     //
// Foundation; either version 2 of the License, or (at your option)  //
// any later version.                                                //
//                                                                   //
// this module is distributed in the hope that it will be useful,    //
// but WITHOUT ANY WARRANTY; without even the implied warranty of    //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.              //
// See the GNU General Public License for more details.              //
//                                                                   //
// You should have received a copy of the GNU General Public License //
// along with this module.  If not, write to:                        //
// 	The Free Software Foundation, Inc.,                              //
// 	51 Franklin Street, Fifth Floor                                  //
// 	Boston, MA  02110-1301, USA.                                     //
///////////////////////////////////////////////////////////////////////
//                                                                   //
//                  Special thanks XProger'ó :)                      //
//                                                                   //
///////////////////////////////////////////////////////////////////////
unit TEXTURE_FORMATS;

interface

{$I DEFINES.pas}

uses
  Windows,
  OpenGL,

  ENGINE_VAR,
  ENGINE_UTILS,

  TEXTURE_MANAGER;

function Tex_LoadData(
                        Mem      : Pointer;
                        MemSize  : Int64;
                        var Tex  : TTexture;
                        var Data : Pointer
                     ) : Boolean;

type
  OLE_HANDLE = LongWord;
  OLE_XPOS_HIMETRIC  = Longint;
  OLE_YPOS_HIMETRIC  = Longint;
  OLE_XSIZE_HIMETRIC = Longint;
  OLE_YSIZE_HIMETRIC = Longint;

  PCLSID = PGUID;
  TCLSID = TGUID;

  POleStr  = PWideChar;
  Largeint = Int64;

  PStatStg = ^TStatStg;
  tagSTATSTG = record
    pwcsName: POleStr;
    dwType: Longint;
    cbSize: Largeint;
    mtime: TFileTime;
    ctime: TFileTime;
    atime: TFileTime;
    grfMode: Longint;
    grfLocksSupported: Longint;
    clsid: TCLSID;
    grfStateBits: Longint;
    reserved: Longint;
  end;
  TStatStg = tagSTATSTG;
  {$EXTERNALSYM STATSTG}
  STATSTG = TStatStg;

  ISequentialStream = interface(IUnknown)
    ['{0c733a30-2a1c-11ce-ade5-00aa0044773d}']
    function Read(pv: Pointer; cb: Longint; pcbRead: PLongint): HResult;
      stdcall;
    function Write(pv: Pointer; cb: Longint; pcbWritten: PLongint): HResult;
      stdcall;
  end;

  IStream = interface(ISequentialStream)
    ['{0000000C-0000-0000-C000-000000000046}']
    function Seek(dlibMove: Largeint; dwOrigin: Longint;
      out libNewPosition: Largeint): HResult; stdcall;
    function SetSize(libNewSize: Largeint): HResult; stdcall;
    function CopyTo(stm: IStream; cb: Largeint; out cbRead: Largeint;
      out cbWritten: Largeint): HResult; stdcall;
    function Commit(grfCommitFlags: Longint): HResult; stdcall;
    function Revert: HResult; stdcall;
    function LockRegion(libOffset: Largeint; cb: Largeint;
      dwLockType: Longint): HResult; stdcall;
    function UnlockRegion(libOffset: Largeint; cb: Largeint;
      dwLockType: Longint): HResult; stdcall;
    function Stat(out statstg: TStatStg; grfStatFlag: Longint): HResult;
      stdcall;
    function Clone(out stm: IStream): HResult; stdcall;
  end;

  IPicture = interface
    ['{7BF80980-BF32-101A-8BBB-00AA00300CAB}']
    function get_Handle(out handle: OLE_HANDLE): HResult;  stdcall;
    function get_hPal(out handle: OLE_HANDLE): HResult; stdcall;
    function get_Type(out typ: Smallint): HResult; stdcall;
    function get_Width(out width: OLE_XSIZE_HIMETRIC): HResult; stdcall;
    function get_Height(out height: OLE_YSIZE_HIMETRIC): HResult; stdcall;
    function Render(dc: HDC; x, y, cx, cy: Longint;
      xSrc: OLE_XPOS_HIMETRIC; ySrc: OLE_YPOS_HIMETRIC;
      cxSrc: OLE_XSIZE_HIMETRIC; cySrc: OLE_YSIZE_HIMETRIC;
      rcWBounds: Pointer): HResult; stdcall;
    function set_hPal(hpal: OLE_HANDLE): HResult; stdcall;
    function get_CurDC(out dcOut: HDC): HResult; stdcall;
    function SelectPicture(dcIn: HDC; out hdcOut: HDC;
      out bmpOut: OLE_HANDLE): HResult; stdcall;
    function get_KeepOriginalFormat(out fkeep: BOOL): HResult; stdcall;
    function put_KeepOriginalFormat(fkeep: BOOL): HResult; stdcall;
    function PictureChanged: HResult; stdcall;
    function SaveAsFile(const stream: IStream; fSaveMemCopy: BOOL;
      out cbSize: Longint): HResult; stdcall;
    function get_Attributes(out dwAttr: Longint): HResult; stdcall;
  end;

  function OleLoadPicture(stream: IStream; lSize: Longint; fRunmode: BOOL;
    const iid: TGUID; var vObject): HResult; stdcall external 'olepro32.dll' name 'OleLoadPicture';

  function CreateStreamOnHGlobal(hglob: HGlobal; fDeleteOnRelease: BOOL;
    var stm: IStream): HResult; stdcall external 'ole32.dll' name 'CreateStreamOnHGlobal';

//----------------------------------------------------------------------------//
                                 IMPLEMENTATION
//----------------------------------------------------------------------------//
uses
  TEXTURE_LOADER, ENGINE_LOG;

procedure CreateBitmap( pPicture : IPicture; var Tex : TTexture; var Data: Pointer );
  var
    bi   : BITMAPINFO;
    bmp  : HBITMAP;
    DC   : HDC;
    p    : Pointer;
    W, H : Integer;
    i    : Integer;
Begin
DC := CreateCompatibleDC( GetDC( 0 ) );
pPicture.get_Width ( W );
pPicture.get_Height( H );
Tex.Width  := MulDiv( W, GetDeviceCaps( DC, LOGPIXELSX ), 2540 );
Tex.Height := MulDiv( H, GetDeviceCaps( DC, LOGPIXELSY ), 2540 );
Tex.U      := 1;
Tex.V      := 1;

FillChar( bi, SizeOf( bi ), 0 );
bi.bmiHeader.biSize	       := SizeOf( BITMAPINFOHEADER );
bi.bmiHeader.biBitCount	   := 32;
bi.bmiHeader.biWidth		   := Tex.Width;
bi.bmiHeader.biHeight	     := Tex.Height;
bi.bmiHeader.biCompression := BI_RGB;
bi.bmiHeader.biPlanes		   := 1;
bmp := CreateDIBSection( DC, bi, DIB_RGB_COLORS, p, 0, 0 );
SelectObject( DC, bmp );
pPicture.Render(
                 DC, 0, 0,
                 Tex.Width,
                 Tex.Height,
                 0, H, W, -H, nil
               );

Mem_Get( Data, Tex.Width * Tex.Height * 4 );
Move   ( p^, Data^, Tex.Width * Tex.Height * 4 );

DeleteObject( bmp );
DeleteDC    ( DC );

if Byte( Pointer( Integer( Data ) + 3 )^ ) = 0 Then
  for i := 0 to Tex.Width * Tex.Height - 1 do
    Byte( Pointer( Integer( Data ) + i * 4 + 3 )^ ) := 255;
End;

function Tex_LoadData;
  var
    m        : Pointer;
    g        : HGLOBAL;
    Stream   : IStream;
    pPicture : IPicture;
Begin

Result := FALSE;
g      := 0;
try
  g := GlobalAlloc( GMEM_FIXED, MemSize );
  m := GlobalLock( g );
  Move( mem^, m^, MemSize );
  GlobalUnlock( g );
  if CreateStreamOnHGlobal( DWORD( m ), FALSE, Stream ) = S_OK Then
    if OleLoadPicture( Stream, 0, FALSE, IPicture, pPicture ) = S_OK Then
      begin
        CreateBitmap( pPicture, Tex, Data );
        Result := TRUE;
      end;
finally
  if g <> 0 Then GlobalFree( g );
end;

Stream   := nil;
pPicture := nil;

End;

end.
