Window - independent rendering contexts

I am using OpenGL on Windows. How can I create a rendering context that is independent of a window? I do not want to render directly to a window, I would rather have OpenGL render directly to an offscreen surface such as a DIB, a block of RGB memory, or to an IDirectDrawSurface. How could I do this?

I don’t think you can because when you create the window you have to specify the pixel format. Just now I’m studyind the same problem and please if you can make something from it say it on the forum because I’m interested.

NewROmancer

Look here:

http://www.opengl.org/discussion_boards/ubb/Forum2/HTML/001072.html

[This message has been edited by Kilam Malik (edited 08-14-2000).]

Thanks, this looks like it will work for me. I’ll post a description of the results.

I used the code from post #8 on the forum you mentioned and it worked the very first time!! Thanks a million!!!

Here’s my source code. It won’t compile because it uses some of my own units but if you take out the unused stuff it will work. The program was written using Delphi 5.

This is actually the beginnings of an OpenGL wrapper I have been working on for a few days. OpenGL programming is way easier than DirectDraw and Direct3DRM!!! Stuff actually does what it is suppose to do!

unit MainForm;

interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
OpenGL12, Oogle
;

type
TfrmMain = class(TForm)
procedure FormPaint(Sender: TObject);
procedure FormCreate(Sender: TObject);

     public
        rc: IOogleRenderDest;

  end;

var
frmMain: TfrmMain;

implementation
{$R *.DFM}

procedure TfrmMain.FormPaint(Sender: TObject);
begin
rc.Start;
try
glBegin(GL_TRIANGLES);
glColor3F(1, 1, 1);
glVertex3F(0, 0, 0);
glVertex3F(0.9, 0, 0);
glVertex3F(1, 1, 0);
glEnd;
finally
rc.Finish;
end;
rc.BitBlt(Canvas.Handle, 0, 0);
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
InitOpenGL;
rc := TOogleRenderDestBitmap.Create(ClientWidth, ClientHeight);
end;

end.

[This message has been edited by skippyj777 (edited 08-14-2000).]

[This message has been edited by skippyj777 (edited 08-14-2000).]

unit MainForm;
// This code was originally formatted with tabs and spacing.

interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
OpenGL12, Oogle
;

type
TfrmMain = class(TForm)
procedure FormPaint(Sender: TObject);
procedure FormCreate(Sender: TObject);

     public
        ogl: IOogle;
        rc: IOogleRenderDest;

  end;

var
frmMain: TfrmMain;

implementation
{$R *.DFM}

procedure TfrmMain.FormPaint(Sender: TObject);
begin
rc.Start;
try
glBegin(GL_TRIANGLES);
glColor3F(1, 1, 1);
glVertex3F(0, 0, 0);
glVertex3F(0.9, 0, 0);
glVertex3F(1, 1, 0);
glEnd;
finally
rc.Finish;
end;
rc.BitBlt(Canvas.Handle, 0, 0);
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
OogleCreate(ogl);
rc := TOogleRenderDestBitmap.Create(ClientWidth, ClientHeight);
end;

end.

unit Oogle;
{$Z+,B-}

// Object-oriented Open GL wrapper. Copyright 2000 Potts Development.

interface
uses
Windows, OpenGL12, Classes
;

type
IOogleObject = interface;
IOogleRenderDest = interface;

  OOGLE_DESTROYCALLBACK = procedure(Sender: IOogleObject; Arg: Pointer) of object;
  pOOGLE_DESTROYCALLBACK_DATA = ^OOGLE_DESTROYCALLBACK_DATA;
  OOGLE_DESTROYCALLBACK_DATA = record
     Callback: OOGLE_DESTROYCALLBACK;
     Arg: Pointer;
  end;

  pOOGLE_APPDATA = ^OOGLE_APPDATA;
  OOGLE_APPDATA = record
     ID: TGUID;
     Data: Pointer;
  end;

  IOogleObject = interface(IUnknown)
     ['{D8866DE5-B56D-4A83-892E-07C17B18F49D}']
     function  GetAppData(const ID: TGUID): Pointer;
     procedure SetAppData(const ID: TGUID; Value: Pointer);
     procedure AddDestroyCallback(cb: OOGLE_DESTROYCALLBACK; Arg: Pointer);
     function  GetName: WideString;
     procedure SetName(Value: WideString);
  end;

  IOogleRenderDest = interface(IOogleObject)
     ['{17479C51-020C-40FE-85DC-F4CC2394DF66}']
     procedure Start;
     procedure Finish;
     procedure BitBlt(DestDC: HDC; DestX, DestY: Integer);
  end;

  TOogleObject = class(TInterfacedObject, IOogleObject)
     protected
        FDestroyCallbacks: TList;
        FAppData: TList;
        FName: WideString;

        procedure ClearAppData;

     public
        constructor Create; virtual;
        destructor Destroy; override;

        function  GetAppData(const ID: TGUID): Pointer;
        procedure SetAppData(const ID: TGUID; Value: Pointer);
        procedure AddDestroyCallback(cb: OOGLE_DESTROYCALLBACK; Arg: Pointer);
        function  GetName: WideString;
        procedure SetName(Value: WideString);

  end;

  TOogleRenderDest = class(TOogleObject, IOogleRenderDest)
     protected
        FRenderContext: HGLRC;
        FStartCount: DWORD;

     public
        constructor Create; override;
        destructor Destroy; override;

        procedure Start; virtual;
        procedure Finish; virtual;
        procedure BitBlt(DestDC: HDC; DestX, DestY: Integer); virtual; abstract;

  end;

  TOogleRenderDestBitmap = class(TOogleRenderDest)
     protected
        FRenderContext: HGLRC;
        FBitmapDC: HDC;

        //FMemoryDC: HDC;
        FBitDepth: Integer;
        FBitmap: HBITMAP;

        FBitmapInfo: BITMAP;

        FPixelFormat: PIXELFORMATDESCRIPTOR;
        FPixelFormatIndex: Integer;

     public
        constructor Create(w, h: Integer); reintroduce;
        destructor Destroy; override;
        procedure Start; override;
        procedure Finish; override;
        procedure BitBlt(DestDC: HDC; DestX, DestY: Integer); override;

  end;

implementation
uses
SysUtils, Messages
;

constructor TOogleObject.Create;
begin
FAppData := TList.Create;
FDestroyCallbacks := TList.Create;
end;

destructor TOogleObject.Destroy;
var
i: Integer;
dc: pOOGLE_DESTROYCALLBACK_DATA;
begin
try
try
for i := 0 to FDestroyCallbacks.Count - 1 do begin
try
dc := FDestroyCallbacks[i];
dc.Callback(Self, dc.Arg);
Dispose(dc);
except
// Ignore
end;
end;
finally
FDestroyCallbacks.Free;
end;
try
ClearAppData;
finally
FAppData.Free;
end;
finally
inherited;
end;
end;

procedure TOogleObject.ClearAppData;
var
i: Integer;
begin
try
for i := 0 to FAppData.Count - 1 do begin
Dispose(FAppData[i]);
end;
finally
FAppData.Clear;
end;
end;

function TOogleObject.GetAppData(const ID: TGUID): Pointer;
var
i: Integer;
ad: pOOGLE_APPDATA;
begin
for i := 0 to FAppData.Count - 1 do begin
ad := FAppData[i];
if PDCompareGUIDs(ID, ad^.ID) then begin
Result := ad^.Data;
Exit;
end;
end;
Result := nil;
end;

procedure TOogleObject.SetAppData(const ID: TGUID; Value: Pointer);
var
i: Integer;
ad: pOOGLE_APPDATA;
begin
for i := 0 to FAppData.Count - 1 do begin
ad := FAppData[i];
if PDCompareGUIDs(ID, ad^.ID) then begin
ad^.Data := Value;
Exit;
end;
end;
New(ad);
try
ad^.ID := ID;
ad^.Data := Value;
FAppData.Add(ad);
except
Dispose(ad);
raise;
end;
end;

procedure TOogleObject.AddDestroyCallback(cb: OOGLE_DESTROYCALLBACK; Arg: Pointer);
var
dc: pOOGLE_DESTROYCALLBACK_DATA;
begin
New(dc);
try
dc^.Callback := cb;
dc^.Arg := Arg;
FDestroyCallbacks.Add(dc);
except
Dispose(dc);
raise;
end;
end;

function TOogleObject.GetName: WideString;
begin
Result := FName;
end;

procedure TOogleObject.SetName(Value: WideString);
begin
FName := Value;
end;

constructor TOogleRenderDest.Create;
begin
inherited;
// Do nothing for now
end;

destructor TOogleRenderDest.Destroy;
begin
try
wglDeleteContext(FRenderContext); // Automatically makes context noncurrent before deleting it
finally
inherited;
end;
end;

procedure TOogleRenderDest.Start;
begin
Inc(FStartCount);
end;

procedure TOogleRenderDest.Finish;
begin
if FStartCount > 0 then Dec(FStartCount);
end;

constructor TOogleRenderDestBitmap.Create(w, h: Integer);
var
FMemoryDC: HDC;
begin
inherited Create;

  FMemoryDC := CreateCompatibleDC(0);
  FBitDepth := GetDeviceCaps(FMemoryDC, BITSPIXEL);
  FBitmap := CreateBitmap(w, h, 1, FBitDepth, nil);
  SelectObject(FMemoryDC, FBitmap);
  FBitmapDC := FMemoryDC;

  GetObject(FBitmap, SizeOf(BITMAP), @FBitmapInfo);

  FPixelFormat.nSize := SizeOf(FPixelFormat);
  FPixelFormat.nVersion := 1;
  FPixelFormat.dwFlags := PFD_DRAW_TO_BITMAP or PFD_SUPPORT_OPENGL or PFD_TYPE_RGBA;
  FPixelFormat.iPixelType := PFD_TYPE_RGBA;
  FPixelFormat.cColorBits := FBitmapInfo.bmBitsPixel;
  FPixelFormat.cDepthBits := 32; // 32-bit depth buffer
  FPixelFormat.iLayerType := PFD_MAIN_PLANE;

  FPixelFormatIndex := ChoosePixelFormat(FBitmapDC, @FPixelFormat);
  if not SetPixelFormat(FBitmapDC, FPixelFormatIndex, @FPixelFormat) then raise Exception.Create('Unable to set pixel format');

  FRenderContext := wglCreateContext(FBitmapDC);
  if FRenderContext = 0 then raise Exception.Create('Unable to create render context');

end;

destructor TOogleRenderDestBitmap.Destroy;
begin
try
wglDeleteContext(FRenderContext);
DeleteObject(FBitmap);
DeleteDC(FBitmapDC);
finally
inherited;
end;
end;

procedure TOogleRenderDestBitmap.Start;
begin
inherited;
if FStartCount = 1 then wglMakeCurrent(FBitmapDC, FRenderContext);
end;

procedure TOogleRenderDestBitmap.Finish;
begin
if FStartCount = 1 then wglMakeCurrent(FBitmapDC, 0);
inherited;
end;

procedure TOogleRenderDestBitmap.BitBlt(DestDC: HDC; DestX, DestY: Integer);
begin
if not Windows.BitBlt(DestDC, DestX, DestY, FBitmapInfo.bmWidth, FBitmapInfo.bmHeight, FBitmapDC, 0, 0, SRCCOPY) then raise Exception.Create(‘Windows.BitBlt() failed’);
end;

end.

[This message has been edited by skippyj777 (edited 08-14-2000).]

I’ll try to look over your code. Thanks anyway.

NewROmancer