Problems priniting an OpenGL image

169 views
Skip to first unread message

Andreas Micheler

unread,
Feb 18, 2006, 2:33:16 PM2/18/06
to wx-u...@lists.wxwidgets.org

Hi group,

I have still problems printing an OpenGL image in high resolution.
The M$VC help says:
<quote>
Printing an OpenGL Image
You can print OpenGL images rendered in enhanced metafiles. When you
render to a printer device (HDC) it must be backed by a metafile
spooler. OpenGL uses memory for depth, color, and other buffers to store
graphics output to a printer. Because typical printer resolution
requires a significant amount of memory to store the graphics output,
printing an OpenGL image might require more memory than is available in
the system. To overcome this limitation, the current implementation of
OpenGL prints OpenGL graphics in bands. However, this increases the time
it takes to print OpenGL images.

Before you print an OpenGL image, you must call the StartDoc function to
complete the initialization of a printer device context (DC). After
calling StartDoc, you can create rendering contexts (HGLRC) to render to
the printer device. If you create rendering contexts before calling
StartDoc, there is no way to determine whether a metafile is spooled.

The following code sample shows how to print an OpenGL image:

HDC hDC;
DOCINFO di;
HGLRC hglrc;

// Call StartDoc to start the document
StartDoc( hDC, &di );

// Prepare the printer driver to accept data
StartPage(hDC);

// Create a rendering context using the metafile DC
hglrc = wglCreateContext ( hDCmetafile );

// Do OpenGL rendering operations here
. . .
wglMakeCurrent(NULL, NULL); // Get rid of rendering context
. . .
EndPage(hDC); // Finish writing to the page
EndDoc(hDC); // End the print job

For more information on using metafiles, see Enhanced Metafile Operations.
</quote>

My code which doesn't draw anything but the test round rectangle so far is:

void Graph::print(wxDC *dc)
{
// beginPrinting(dc);
// recorder->playAgain();
// endPrinting(dc);

printing=true;
HDC oldDC=wglGetCurrentDC();
HGLRC oldContext=wglGetCurrentContext();
// Create a rendering context using the metafile DC
HGLRC hglrc;
int w, h;
dc->GetSize(&w, &h);
wxMetafileDC mdc(wxEmptyString, w,h);
setDCPixelFormat((HDC)mdc.GetHDC(),
PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL);
hglrc = wglCreateContext((HDC)mdc.GetHDC());

// Do OpenGL rendering operations here
int result=wglMakeCurrent((HDC)mdc.GetHDC(), hglrc);
setOpenGLState();

if(h > 0)
{ glViewport(0, 0, w, h);
oldRect.SetWidth(w);
oldRect.SetHeight(h);
setFrustum(w, h);
screen->getMatrices();
}
recorder->stop();
screen->destroy();
screen->create(w,h);
recorder->playAgain();

mdc.DrawRoundedRectangle(0,0,100,100,20);
wxMetafile *mf=mdc.Close();
mf->Play(dc);
delete mf;
wglMakeCurrent(oldDC, oldContext);
wglDeleteContext(hglrc);
printing=false;
}

Graph is a wxGLCanvas derived class, dc is a wxPrinterDC obtained from
the wx printing framework, taken from the printing example.
recorder->playAgain() draws the OpenGL image, but I only see the round
rectangle, either in the print preview or in the printout.

Where's my mistake?

Thanks for any suggestions,
Andreas


Andreas Micheler

unread,
Feb 18, 2006, 10:18:17 PM2/18/06
to wx-u...@lists.wxwidgets.org

Hi again,

I got the high resolution OpenGL printing running now.
This is my printing code for Windows
(so others can easily use it):

void Graph::print(wxDC *dc)
{


printing=true;
HDC oldDC=wglGetCurrentDC();
HGLRC oldContext=wglGetCurrentContext();

int w, h;
dc->GetSize(&w, &h);

BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));

BITMAPINFOHEADER bmiHeader=
{ sizeof(BITMAPINFOHEADER), //biSize
w, //biWidth
h, //biHeight
1, //biPlanes
24, //biBitCount
BI_RGB, //biCompression
w*h*4, //biSizeImage
};
bmi.bmiHeader=bmiHeader;

HDC hDC = ::GetDC((HWND)m_hWnd);
LPVOID bitmapBits;
HBITMAP dib = ::CreateDIBSection(
hDC, &bmi, DIB_RGB_COLORS, &bitmapBits, NULL, (DWORD)0);
::ReleaseDC((HWND)m_hWnd, hDC);

HDC mdc=::CreateCompatibleDC(0);
HBITMAP oldbm = (HBITMAP)SelectObject(mdc, dib);

setDCPixelFormat(mdc,
PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL);

HGLRC rc=wglCreateContext(mdc),
oldrc=wglGetCurrentContext();
wglMakeCurrent(mdc, rc);
// here begins the drawing of the OpenGL scene
glViewport(0,0, w,h);
setFrustum(w,h);
setOpenGLState();

screen->getMatrices();

wxSize saveWinsize(screen->winsizex, screen->winsizey);
screen->winsizex=w;
screen->winsizey=h;

ftglFontManager->clear();

saving=true;
recorder->playAgain(); // here the drawing takes place
saving=false;
// here ends the drawing of the OpenGL scene

int dummy;
glReadPixels(0,0, 0,0, GL_RGB, GL_UNSIGNED_BYTE, &dummy);

BitBlt((HDC)dc->GetHDC(), 0,0, w,h, mdc, 0,0, SRCCOPY);

wglMakeCurrent(oldDC, oldContext);
wglDeleteContext(rc);
DeleteObject(dib);
DeleteDC(mdc);
screen->winsizex=saveWinsize.GetWidth();
screen->winsizey=saveWinsize.GetHeight();

printing=false;
}

Graph is a wxGLCanvas derived class.

What I want to ask now is, what about the memory consumption?
OpenGL printing using the printer resolution takes hundreds of
megabytes. Is there a possibility to print in bands, which fit into
memory? How could this be achieved with wxWidgets? Or is it hidden
somewhere?

Thanks,
Andreas


Reply all
Reply to author
Forward
0 new messages