青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

OpenGL打印&&預覽

Printing and Print Preview OpenGL in MFC
Rating:

Wenfei Wu (view profile)
February 14, 2001

Wrapping OpenGL with MFC can take the advantages of both APIs: fast rendering and an elegant GUI. However, due to the fact that many printer drivers do not work with the SetPixelFormat() API function, it is not feasible to render an OpenGL scene to a printer directly. A widely used technique is to render an OpenGL scene to a DIB section, then copy it to a DC for printing or print preview. This article demonstrates this approach.
(continued)

I use Document/View architecture in the demo. The view class CGLView is multiple-derived from CView and CGLObj. The later class bundles all the OpenGL implementation - including printing. The CGLView::OnPrint function wraps three methods as follows:

void CGLView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{	CGLObj::OnPrint1(pDC, pInfo, this);
	// TODO: Render header here.
	OnDraw(pDC);
	// TODO: Render footer here.
	CGLObj::OnPrint2(pDC);
}

The CGLObj::OnPrint1 is designed to prepare for off-screen rendering. The major purposes of the method are to create a DIB section, and a memory RC. The memory RC will be used for OpenGL off-screen rendering later on. Following is the sequential of the method. After rendering, CGLObj::OnPrint2 copies the image in DIB section to the printer or preview DC, then releases the memory.

Preparing for OpenGL Off-Screen Rendering - OnPrint1()

  1. Determine the DIB size for either printing or print preview.

    The size of the DIB section depends on the size of the display device. For print previewing, I use screen resolution. For printing, I use the reduced printer's resolution. Ideally, I hope I can use the printer's full resolution if memory and speed is not a problem. However, for a printer with 720 DPI and using letter-sized paper, the memory of a DIB section is easily to excess of 100MB. That is why I reduce the printing resolution.

  2. Create DIB Section

    I call Windows function CreateDIBSection() to create a DIB section with this size mentioned above.

  3. Create memory DC, and associate it with the DIB section

    Calling Win32 function CreateCompatibleDC() creates a memory DC and returns a handle of it. Then I select the DIB section into a memory DC.

  4. Setup memory DC's pixel format

    Setting memory DC's pixel format is similar to setup a screen DC. The only difference is a flag specifying properties of the pixel buffer. I set PFD_DRAW_TO_WINDOW and PFD_DOUBLEBUFFER for the screen DC, but I need PFD_DRAW_TO_BITMAP for the memory DC. Thus, I made a helper function SetDCPixelFormat() to reuse this part of code.

  5. Create memory RC

    I use the above memory DC to create a memory RC for OpenGL off-screen rendering. The life of memory DC and RC will end when the printing is finished.

  6. Store old DC and RC

    The DC and RC for screen rendering should be stored. They will be restored after printing is finished.

  7. Make the memory RC current

    The function wglMakeCurrent() sets the memory RC current. From now, OpenGL will render with the memory RC, not screen RC. However, before rendering with the memory RC, I have to initialize the RC just like that working with screen RC.

  8. Set OpenGL state for memory RC

    The OpenGL state and frustum of the memory RC must be the same as the screen RC's so that we can get the same image rendered to the memory RC. I made SetOpenGLState() and SetFrustum() functions work for both RCs

  9. Create display list with the newly created memory RC.

    If you use OpenGL display list, you must create it again with the newly created memory RC. Keep in mind the display list is not reusable across RCs.

Following is the source code of CGLObj::OnPrint1

void CGLObj::OnPrint1(CDC* pDC, CPrintInfo* pInfo, CView* pView)
{
 // 1. Determine the DIB size for either printing or print preview.
 CRect rcClient;
 pView->GetClientRect(&rcClient);
 float fClientRatio = float(rcClient.Height())/rcClient.Width();

 // Get page size
 m_szPage.cx  = pDC->GetDeviceCaps(HORZRES);
 m_szPage.cy = pDC->GetDeviceCaps(VERTRES);

 CSize szDIB;
 if (pInfo->m_bPreview)
 {
  // Use screen resolution for preview.
  szDIB.cx = rcClient.Width();
  szDIB.cy = rcClient.Height();
 }
 else  // Printing
 {
  // Use higher resolution for printing.
  // Adjust size according screen's ratio.
  if (m_szPage.cy > fClientRatio*m_szPage.cx)
  {
   // View area is wider than Printer area
   szDIB.cx = m_szPage.cx;
   szDIB.cy = long(fClientRatio*m_szPage.cx);
  }
  else
  {
   // View area is narrower than Printer area
   szDIB.cx = long(float(m_szPage.cy)/fClientRatio);
   szDIB.cy = m_szPage.cy;
  }

  // Reduce the Resolution if the Bitmap size is too big.
  // Ajdust the maximum value, which is depends on printer's memory.
  // I use 20 MB.
  while (szDIB.cx*szDIB.cy > 20e6)
  {
   szDIB.cx = szDIB.cx/2;
   szDIB.cy = szDIB.cy/2;
  }
 }

 TRACE("Buffer size: %d x %d = %6.2f MB\n",
 szDIB.cx, szDIB.cy, szDIB.cx*szDIB.cy*0.000001);

 // 2. Create DIB Section
 memset(&m_bmi, 0, sizeof(BITMAPINFO));
 m_bmi.bmiHeader.biSize		= sizeof(BITMAPINFOHEADER);
 m_bmi.bmiHeader.biWidth		= szDIB.cx;
 m_bmi.bmiHeader.biHeight		= szDIB.cy;
 m_bmi.bmiHeader.biPlanes		= 1;
 m_bmi.bmiHeader.biBitCount	= 24;
 m_bmi.bmiHeader.biCompression	= BI_RGB;
 m_bmi.bmiHeader.biSizeImage	= szDIB.cx * szDIB.cy * 3;

 HDC	hDC = ::GetDC(pView->m_hWnd);
 m_hDib = ::CreateDIBSection(hDC, &m_bmi, DIB_RGB_COLORS,
 &m_pBitmapBits, NULL, (DWORD)0);
 ::ReleaseDC(pView->m_hWnd, hDC);

 // 3. Create memory DC, and associate it with the DIB.
 m_hMemDC = ::CreateCompatibleDC(NULL);
 if (!m_hMemDC)
 {
  DeleteObject(m_hDib);
  m_hDib = NULL;
  return;
 }
 SelectObject(m_hMemDC, m_hDib);

 // 4. Setup memory DC's pixel format.
 if (!SetDCPixelFormat(m_hMemDC,
                       PFD_DRAW_TO_BITMAP
                       | PFD_SUPPORT_OPENGL
                       | PFD_STEREO_DONTCARE))
 {
  DeleteObject(m_hDib);
  m_hDib = NULL;
  DeleteDC(m_hMemDC);
  m_hMemDC = NULL;
  return;
 }

 // 5. Create memory RC
 m_hMemRC = ::wglCreateContext(m_hMemDC);
 if (!m_hMemRC)
 {
  DeleteObject(m_hDib);
  m_hDib = NULL;
  DeleteDC(m_hMemDC);
  m_hMemDC = NULL;

  return;
 }

 // 6. Store old DC and RC
 m_hOldDC = ::wglGetCurrentDC();
 m_hOldRC = ::wglGetCurrentContext();

 // 7. Make the memory RC current
 ::wglMakeCurrent(m_hMemDC, m_hMemRC);

 // 8. Set OpenGL state for memory RC.
 // The state is the same as the screen RC's.
 SetOpenGLState();
 ::glViewport(0, 0, szDIB.cx, szDIB.cy);
 SetFrustum();

 // 9. Create display list with the newly created memory RC
 CreateDisplayList(1);
}

Off-Screen Rendering

Now we can render with the memory RC. It is a common practice and a good idea to reuse the rendering scenario, but do not use double buffering for the memory RC.
Printing - OnPrint2()
This method handles the real "printing", and then free the memory.
  1. Release memory RC, and restore the old DC and RC.

    After rendering, we can delete the memory RC right away, and restore the old DC and RC for screen rendering.

  2. Calculate the target size according to the image size, and orientation of the paper.

    Now the image is stored in the memory, particularly in the DIB section. In general, the page size and orientation are different from the image's. We need to work out a target area on the page, to which the image will be copied. The target area should have the same orientation and elongation as the image in the DIB section.

  3. Stretch image to fit in the target size.

    The Win32 API StretchDIBits() copies the image in the DIB section to the destination, a handle to DC for either printing or print preview. The image is stretched to fit in the target area with the same elongation.

  4. Release memory.

    The job is finished. Release the memory for DIB section and memory DC now.

Following is the source code of CGLObj::OnPrint2

void CGLObj::OnPrint2(CDC* pDC)
{
 // Now the image is in the DIB already. We don't need the
 // memory RC anymore. We'll copy the image to the DC for
 // printing or print preview.

 // 1. Release memory RC, and restore the old DC and RC.
 ::wglMakeCurrent(NULL, NULL);
 ::wglDeleteContext(m_hMemRC);

 // Restore last DC and RC
 ::wglMakeCurrent(m_hOldDC, m_hOldRC);

 // 2. Calculate the target size according to the image size,
 //    and orientation of the paper.
 float fBmiRatio =
 float(m_bmi.bmiHeader.biHeight) / m_bmi.bmiHeader.biWidth;

 CSize szTarget;
 if (m_szPage.cx > m_szPage.cy)	 // Landscape page
 {
  if(fBmiRatio<1)	  // Landscape image
  {
   szTarget.cx = m_szPage.cx;
   szTarget.cy = long(fBmiRatio * m_szPage.cx);
  }
  else			  // Portrait image
  {
   szTarget.cx = long(m_szPage.cy/fBmiRatio);
   szTarget.cy = m_szPage.cy;
  }
 }
 else		    // Portrait page
 {
  if(fBmiRatio<1)	  // Landscape image
  {
   szTarget.cx = m_szPage.cx;
   szTarget.cy = long(fBmiRatio * m_szPage.cx);
  }
  else			  // Portrait image
  {
   szTarget.cx = long(m_szPage.cy/fBmiRatio);
   szTarget.cy = m_szPage.cy;
  }
 }

 CSize szOffset((m_szPage.cx - szTarget.cx) / 2,
                (m_szPage.cy - szTarget.cy) / 2);

 // 3. Stretch image to fit in the target size.
 int nRet = ::StretchDIBits(pDC->GetSafeHdc(),
                            szOffset.cx, szOffset.cy,
                            szTarget.cx, szTarget.cy,
                            0, 0,
                            m_bmi.bmiHeader.biWidth,
                            m_bmi.bmiHeader.biHeight,
                            GLubyte*) m_pBitmapBits,
                            m_bmi,
                            DIB_RGB_COLORS,
                            SRCCOPY);

 if(nRet == GDI_ERROR)
  TRACE0("Failed in StretchDIBits()");

 // 4. Release memory.
 DeleteObject(m_hDib);
 m_hDib = NULL;
 DeleteDC(m_hMemDC);
 m_hMemDC = NULL;
 m_hOldDC = NULL;
}

Notice

This demo requires at least 16 bit colors. If your computer displays blank in print preview, check out the color setting in the Control Panel.

Not all video cards work well with OpenGL. When you involve any problem, try with machines with different video chards.

Downloads

Download source - 37 Kb

posted on 2006-01-25 00:25 zmj 閱讀(2664) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            麻豆成人精品| 亚洲国产精彩中文乱码av在线播放| 亚洲一区二区精品在线| 亚洲精品久久久一区二区三区| 免费一级欧美在线大片| 欧美激情一级片一区二区| 亚洲国产精品一区二区尤物区 | 亚洲综合色视频| 一区二区三区精品久久久| 亚洲欧美日本精品| 久久精品国产v日韩v亚洲 | 正在播放欧美一区| 欧美午夜激情小视频| 夜夜嗨av一区二区三区四区| 亚洲第一精品电影| 欧美xart系列在线观看| 亚洲精品在线观看视频| 亚洲精品国产精品乱码不99| 欧美伦理一区二区| 亚洲性线免费观看视频成熟| 一本色道久久综合狠狠躁篇怎么玩| 欧美精品在线免费| 欧美fxxxxxx另类| 在线精品观看| 亚洲国产精品久久91精品| 欧美不卡福利| 一本大道久久a久久精二百| 日韩亚洲欧美中文三级| 欧美性色aⅴ视频一区日韩精品| 亚洲在线中文字幕| 新狼窝色av性久久久久久| 韩国一区电影| 欧美激情一区二区三区全黄| 欧美激情免费观看| 亚洲女人av| 久久成人资源| a4yy欧美一区二区三区| 亚洲一区精品视频| 在线精品福利| 在线综合+亚洲+欧美中文字幕| 国产精品色午夜在线观看| 久久亚洲一区二区| 欧美福利电影网| 亚洲免费视频中文字幕| 久久久久国产一区二区| 在线中文字幕日韩| 欧美一区二区在线观看| 亚洲人成人一区二区三区| 一本色道88久久加勒比精品| 国产一区再线| 亚洲精品免费一二三区| 国产午夜亚洲精品不卡| 亚洲黄色成人网| 国产视频一区三区| 91久久黄色| 国产一区二区三区在线观看精品| 亚洲国产二区| 激情欧美日韩一区| 亚洲天堂第二页| 亚洲精品黄网在线观看| 欧美亚洲免费高清在线观看| 日韩亚洲精品电影| 久久久www成人免费精品| 久久国产福利| 91久久精品国产91久久性色| 亚洲国产99| 国产视频观看一区| 一区二区不卡在线视频 午夜欧美不卡在 | 亚洲精品国精品久久99热一| 国产日韩综合| 日韩午夜av| 亚洲激情一区二区| 亚洲欧美日韩区| 亚洲特级毛片| 欧美国产精品| 免费一级欧美在线大片| 韩国精品主播一区二区在线观看| 一区二区三区福利| 一本色道久久综合亚洲精品婷婷 | 欧美bbbxxxxx| 欧美风情在线观看| 尹人成人综合网| 亚洲欧美日本伦理| 亚洲一区在线播放| 欧美区一区二| 亚洲第一在线综合在线| 在线成人h网| 久久看片网站| 麻豆精品一区二区av白丝在线| 国产日韩一区在线| 午夜精品一区二区三区在线| 欧美在线亚洲在线| 国产欧美亚洲一区| 亚洲女同性videos| 欧美一区二区精品| 国产免费成人在线视频| 亚洲一区二区三区四区五区黄| 夜夜夜久久久| 欧美午夜美女看片| 在线综合欧美| 欧美一区二区免费视频| 国产精品一区二区在线观看网站| 亚洲午夜免费福利视频| 香蕉久久国产| 国产亚洲精品一区二555| 欧美在线影院| 欧美成人自拍| 日韩手机在线导航| 欧美日韩成人综合| 一本综合久久| 欧美日韩一区在线观看视频| 9久re热视频在线精品| 亚洲欧美日韩视频一区| 国产午夜一区二区三区| 久久精品二区三区| 亚洲国产成人不卡| 亚洲一区二区在线免费观看| 国产欧美一区二区三区国产幕精品| 午夜国产不卡在线观看视频| 久久亚洲春色中文字幕久久久| 亚洲国产精品久久久久久女王| 欧美激情中文字幕一区二区| 亚洲视频图片小说| 欧美在线观看视频一区二区三区| 亚洲五月婷婷| 国产精品二区影院| 香蕉久久久久久久av网站| 久久综合久久综合久久综合| 亚洲精品视频在线| 国产精品扒开腿做爽爽爽软件 | 精品不卡一区二区三区| 欧美va亚洲va国产综合| 一区二区三区鲁丝不卡| 久久亚洲精品一区| 亚洲婷婷综合色高清在线| 国产一区自拍视频| 欧美日韩国产欧| 欧美一区二区视频观看视频| 亚洲黄色毛片| 久久精品一区四区| 一区二区不卡在线视频 午夜欧美不卡'| 国产日韩在线视频| 欧美日韩一区二区在线观看 | 国产曰批免费观看久久久| 欧美激情在线有限公司| 久久精品国亚洲| 亚洲少妇自拍| 亚洲激情社区| 欧美成人在线网站| 久久米奇亚洲| 午夜精品久久久久久久99水蜜桃| 亚洲精品麻豆| 在线播放豆国产99亚洲| 国产精品一区二区三区乱码 | 亚洲国产第一| 国产午夜精品一区二区三区欧美| 欧美三日本三级少妇三2023 | 亚洲经典一区| 午夜视频久久久| 日韩一本二本av| 亚洲三级影片| 亚洲啪啪91| 亚洲国语精品自产拍在线观看| 久久免费视频网| 欧美在线观看视频| 亚洲欧洲99久久| 亚洲综合三区| 亚洲一区二区三区久久| 亚洲最黄网站| 亚洲精品一二| 99视频超级精品| 日韩午夜在线视频| 99热在这里有精品免费| 亚洲精品在线免费| 99精品99| 一区二区三区av| 亚洲视频播放| 亚洲一区美女视频在线观看免费| 妖精视频成人观看www| 一区二区三区久久精品| 宅男在线国产精品| 亚洲网站在线观看| 亚洲在线观看免费| 午夜精品在线视频| 久久本道综合色狠狠五月| 欧美在线看片a免费观看| 久久国产福利国产秒拍| 久久久一二三| 亚洲电影下载| 日韩视频免费观看| 亚洲一区二区欧美| 久久aⅴ国产紧身牛仔裤| 久久亚洲视频| 欧美精品一区二区三区蜜桃| 在线一区二区视频| 欧美激情影院| 日韩视频免费在线| 午夜精品一区二区三区电影天堂 | 亚洲免费精彩视频| 亚洲女ⅴideoshd黑人|