Printing OpenGL in MFC

I have seen a number of OpenGL view classes in various magazines. NONE of them addressed printing. Sigh.

So, suppose you have an OpenGL view class with member data storing the HGLRC and CDC (which are required for an OpenGL-enabled window):

class COpenGLView : public CView {
	...
protected:
	CDC *m_pDC;
	HGLRC m_hRC;
	...
};
In your OnCreate override, you will create these:
int COpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct) {
	if (CView::OnCreate (lpCreateStruct) == -1) return (-1);
	m_pDC = new CClientDC (this);
	if (m_pDC == NULL) return (-1);
	//  Set the DC's pixel format...
	if (!SetDCPixelFormat (m_pDC)) return (-1);
	m_hRC = wglCreateContext (m_pDC->GetSafeHdc ());
	if (!wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)) return (-1);
	glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
	glClearDepth (1.0);
	return (0);
}

Notice that I call wglMakeCurrent () here. Some authors do it at the beginning of OnDraw (). That is probably because their code didn't work without it! Bear in mind that wglMakeCurrent () makes a specific window instance the current OpenGL window. In an MDI, with two documents open, you need to make sure that each view instance makes its own window current before drawing into it. Therefore, calling wglMakeCurrent () in OnCreate () is not enough -- otherwise after the second view is created, all subsequent OpenGL calls in the first view will get rendered in the second!

Many authors call wglMakeCurrent () at the beginning of the view's OnDraw() method -- resist the temptation! Here is (roughly) my COpenGLView::OnPrint():
void COpenGLView::OnPrint(CDC* pDC, CPrintInfo* pInfo) {
	//  Let's not worry for now about print preview...
	if (pInfo->m_bPreview) return;  //  or print a message to preview
	window...
		
		UINT CurPage = pInfo->m_nCurPage;
	GLsizei HRes = pDC->GetDeviceCaps(HORZRES);
	GLsizei VRes = pDC->GetDeviceCaps(VERTRES);
	GLsizei HPixelsPerInch = pDC->GetDeviceCaps(LOGPIXELSX);
	GLsizei VPixelsPerInch = pDC->GetDeviceCaps(LOGPIXELSY);
	pDC->SetMapMode (MM_TEXT);
	// m_LMargin, etc are margins, in inches...
	GLint l = (GLint) (m_LMargin*HPixelsPerInch);
	GLint r = (GLint) (m_RMargin*HPixelsPerInch);
	GLint t = (GLint) (m_TMargin*VPixelsPerInch);
	GLint b = (GLint) (m_BMargin*VPixelsPerInch);
	//  Image width and height...
	GLsizei w = HRes - l - r;
	GLsizei h = VRes - t - b;
	//  Probably don't need this...
	int SavedDC = pDC->SaveDC ();
	if (CurPage == 1) {
		//  Save the current OpenGL settings...
		HDC   hDCOld   = wglGetCurrentDC ();
		HGLRC hGLRCOld = wglGetCurrentContext ();
		//  Make the printer the current
		//  OpenGL rendering device...
		HGLRC hGLRCPrinter = wglCreateContext (pDC->GetSafeHdc ());
		BOOL bRet = wglMakeCurrent (pDC->GetSafeHdc (), hGLRCPrinter);
		
		ASSERT (bRet);
		glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
		glClearDepth (1.0);
		//  This makes a square image...
		if (w < h) h = w;
		if (h < w) w = h;
		//  This centers the images...
		l = (HRes - w)/2;
		b = (VRes - h)/2;
		//
		glViewport(l, b, w, h);
		OnDraw (pDC);
		//  Go back to the saved OpenGL settings...
		wglMakeCurrent (hDCOld, hGLRCOld);
		wglDeleteContext(hGLRCPrinter);
	}
	//  Probably don't need this...
	if (SavedDC != 0) pDC->RestoreDC (SavedDC);
}

Notice that OnPrint () calls OnDraw (). If in OnDraw () you were to call wglMakeCurrent (), you would no longer be printing...you would be redrawing the view! It should also be noted that setting and restoring the current OpenGL device can be done in OnBeginPrinting () and OnEndPrinting (); for simplicity, I have put all the code here.

So, now printing OpenGL is simple. Let's go back to drawing...

In order to make sure your drawing goes to the correct window, you need to call wglMakeCurrent from SOMEWHERE OTHER THAN OnDraw (). But where? The candidates are OnActivateView () and OnUpdate ().

Some of the time, calling it in an override of OnActivateView () might be enough. However, there is one scenario where this will not be enough: MDI apps when you have created a second CMDIChildWnd frame via the New Window item in the Window menu. This creates additional views into the same document. Now you can have the situation where the active view does something which causes the document to call UpdateAllViews (), which calls the inactive view's OnUpdate () method, which will draw into the wrong window!

Alternatively, you can override OnUpdate (), and call wglMakeCurrent () there. You might be tempted to do this:

void COpenGLView::OnUpdate (CView* pSender, LPARAM lHint, CObject* pHint) {
	wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC);
	CView::OnUpdate (pSender, lHint, pHint);
}

Unfortunately, this won't work all the time. CView::OnUpdate () simply invalidates the view's window, which generates a WM_PAINT message. This WM_PAINT is queued up, and handled at some later time...in particular, possibly after calling another view's OnUpdate () method (that is, after another window has been made the current OpenGL rendering device). There is only one conclusion: you must call OnDraw () directly from OnUpdate () (and don't call the base class CView::OnUpdate ()). There are, of course, performance issues, but I generally ignore them.

Therefore, I usually override both methods: OnActivateView () and OnUpdate (), and I call wglMakeCurrent () in both. However, in OnUpdate (), I save and restore the current settings at the beginning and end of the method (just like in OnPrint ()). This is not necessary in OnActivateView ().

void COpenGLView::OnActivateView(BOOL bActivate,
								 CView* pActivateView, CView* pDeactiveView) {
	CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
	if (bActivate) {
		wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC);
	}
}
void COpenGLView::OnUpdate (CView* pSender, LPARAM lHint, CObject* pHint) {
	//  Save the current OpenGL settings...
	HDC   hDCOld   = wglGetCurrentDC ();
	HGLRC hGLRCOld = wglGetCurrentContext ();
	//  Make this view the current OpenGL rendering context...
	BOOL bRet = wglMakeCurrent (m_pDC, m_hRC);
	//  Draw!!!
	OnDraw (m_pDC);
	//  Go back to the saved OpenGL settings...
	wglMakeCurrent (hDCOld, hGLRCOld);
	wglDeleteContext(hGLRCPrinter);
}

The reason to return to the previous settings in OnUpdate () is fairly subtle. Suppose you didn't, and the last view to be redrawn was not the active view. Suppose you then handled a mouse event in the active view, and you called one of the OpenGL calls that translated the mouse point into an (x,y,z) coordinate. It would translate it based upon the current OpenGL settings (ie. viewport, rotations, scalings, etc). If the two views were not identical, you would end up with improper translations. Since I use the mouse to translate, scale, etc, this is very important! In any case, by setting the current context in OnActivate (), and restoring the previous settings at the end of OnUpdate (), the active view is the current OpenGL context when the next (mouse or other) event occurs.

Now for print preview: I dunno! I tried to do it, but it did not work. I basically could not get the CDC configured to handle OpenGL. I don't know WHAT I was doing wrong. If anyone can get it working correctly, please, PLEASE let me know. It bugs the snot out of me!

In summary, I have tried to not only show the main printing solution, but have also tried to explain in detail some of the subtle problems that show up. Hopefully, the discussion will give you a better understanding of the issues involved, so that if you run into other OpenGL problems, you will be better equipped to deal with them.

John Wagner
Institute of Theoretical Dynamics
UC Davis



Comments

  • Nike spring/summer 2013 released Unoccupied Chukka Woven shoes

    Posted by aronottociome on 04/25/2013 12:33am

    Nike Lunar Flyknit Chukka launched earlier this year as members of the known favorable the rage footwear, maker of footwear [url=http://www.nikeskorrea.se/nike-air-max-1-c-41/]air max 1[/url] as recently created Rationale, created another pair of new sneakers Unrestricted Chukka Woven. Different from the ex-, new uppers made of Woven name brand one knitting technology, Chukka shoe shape on the surface carries on Nike Without cost or obligation 3 soles, with special shore up and the shocker features, coupled with unstarched texture, with a barefoot wearing experience. This [url=http://www.nikeskornatet.se/]köpa nike air max[/url] Night Stadium/Sport Cool Grey/Hyper Indecent and Turquoise shoes convenient in two color schemes, in counting up to textile uppers, gleam systematize old on Suede Ankle niceties german autobahn built unmistakably blocked insensible footwear rounds of galleries. [url=http://www.nikeskorrea.se/]nike löparskor[/url] Unrestrained Chukka Woven which are already launched, interested friends may want to demand brands specified retailers such as Overkill in search details.

    Reply
  • You pine for some tomato basil and mozzarella. In favour of indoor depress into service, these slippers are as well-lighted and manueverable as sneakers.

    Posted by Soaceddew on 04/24/2013 05:21pm

    Has only released respective chic color Democratic Inneva Woven shoes, Nike recently with another direction to bring shoes with different styling to all [url=http://markwarren.org.uk/property-waet.cfm]air max 90 uk[/url] eyes. This brings steadfast printing Unfastened Inneva Woven is a Fair-skinned Label of works in the series, represents shoes Italian made the assurance. Latest Allowed Inneva Woven clouded and pornographic are on tap in two color schemes, to hand-knit Woven vamp in addition to infiltrated Italy's [url=http://markwarren.org.uk/goodbuy.cfm]nike free uk[/url] finest crafts, meanwhile gives athletes terminate to the foot of comfort, the most consequential opportunity is the outclass of Free 5 configuration, barefoot consider it resolution give birth to cannot be ignored. Nike Free Inneva Woven SP Pale-complexioned Characterization Pack on Parade 16 at outlets about the [url=http://markwarren.org.uk/property-waet.cfm]air max 90 uk[/url] trade-mark on the shelves, and on sale in minimal sort, interested friends should recompense terminate publicity to Nike announced the news.

    Reply
  • How to print a view containing both openGL and GDI drawings?

    Posted by RaviStrs on 11/09/2006 01:42am

    Could you please spend some time to look at my query? Along with OpenGL drawing, my application view have some other drawings on screen (pDC->LineTo,Rectangle etc..)to show some legends on screen. On printing I need to add the GDI drawings also to the existing DIB. Could you please suggest me some guide line to do that? I have used GDI commands in OnDraw() function of view class. Thank you.

    Reply
  • proplem

    Posted by Legacy on 10/16/2003 12:00am

    Originally posted by: nora

    i want to know how i can connect visualc++6 with opengl or how download opengl
    thankyou

    Reply
  • Another approach

    Posted by Legacy on 07/11/2002 12:00am

    Originally posted by: Uwe Kotyczka

    Creating a HGLRC for a printer device context using
    
    wglCreateContext returns NULL in most cases. Somewhere
    I've read that the printer must support at least 4
    bitplanes to be supported by OpenGl.

    I decided to render to a DIB (device independend bitmap)
    and then to blit it to the printer. Works fine on all
    printers I have tried it.

    For source code have a look at my demo
    http://www.8ung.at/kotyczka/opengl_en.html.

    Uwe Kotyczka.
    uwe.kotyczka@web.de


    Reply
  • Direct print seems very very slow?

    Posted by Legacy on 04/25/2002 12:00am

    Originally posted by: Tony Yuan

    Did you have this feeling? A very simple picture will take me over 10 min.s.

    Reply
  • WorldTransForm

    Posted by Legacy on 02/18/2001 12:00am

    Originally posted by: Yahua Li

    Who can help me to get the information about WorldTransForm
    in detail.

    Reply
  • Using OpenGL to resize image files

    Posted by Legacy on 01/23/2000 12:00am

    Originally posted by: Charlie Hu

    How to transfer the image files(GIF/JEPG) into the ones with specified size(200pi*200pi) by using OpenGL?

    Reply
  • About openGL hrc on print...

    Posted by Legacy on 09/14/1999 12:00am

    Originally posted by: Leo

    I try to printting openGL graphics. but I fail to create the context device of openGL. I got some infomation from a book . It tell me that openGL can not be print directly because of the memory limited. Metafile must be used as intermedia when printting. But the metafile can contain only the GDI commands, it make me more and more ambiguous !
    You can make me more clear!
    Thanks.
    Leo

    Reply
  • MFC Programmer's SourceBook - OpenGL -PRINTING ON OPENGL IN MFC

    Posted by Legacy on 07/20/1999 12:00am

    Originally posted by: Anbumani

    Please Attach the Sample WorkSpace.
    
    That will very useful to understand.
    Thankx in Advance.
    Anbumani

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IT decision support impacts all aspects of technology management, from governance and strategy to budgets and resource planning. IT decision support effectiveness often falls prey to data-driven challenges that make it difficult to understand the data in context. These challenges: overwhelming data volumes, heterogeneous data types, and growing data complexity. This Forrester Consulting Paper reports the three key findings from their study conducted, on behalf of BDNA, to test the hypothesis that data …

  • Specialization and efficiency are always in need. Whether it's replacing an aging roof, getting a haircut, or tuning up a car, most seek the assistance of trusted experts. The same is true in the business world, where an increasing number of companies are seeking the help of others to administer their IT systems and services. This special edition of Unleashing IT highlights a new breed of IT caretaker -- Cisco Powered service providers -- and the business advantages and operational efficiencies they …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds