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

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 閱讀(2669) 評論(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一区av二区av| 久久综合99re88久久爱| 免费久久99精品国产自| 日韩亚洲欧美在线观看| 亚洲一区二区三区乱码aⅴ蜜桃女| 国产精品人人爽人人做我的可爱 | 亚洲精品一二| 99这里只有久久精品视频| 国产精品露脸自拍| 玖玖在线精品| 欧美日韩在线一区| 久久男人资源视频| 欧美精品一区二区高清在线观看| 在线亚洲一区观看| 欧美一区三区三区高中清蜜桃| 精久久久久久| 一区二区欧美在线| 永久555www成人免费| 亚洲国产你懂的| 国产精品国产亚洲精品看不卡15| 午夜精品视频在线观看一区二区| 久久男女视频| 午夜精品福利视频| 美女网站久久| 久久国产欧美日韩精品| 欧美激情一区二区三区在线视频观看| 亚洲欧美三级伦理| 免费成人av在线| 久久成人精品一区二区三区| 欧美国产亚洲另类动漫| 久久精品视频va| 欧美日韩国产一区二区三区| 久久久久久色| 国产精品日韩久久久| 亚洲高清自拍| 精品不卡一区| 性欧美超级视频| 亚洲自拍偷拍福利| 欧美激情一级片一区二区| 久久久免费观看视频| 欧美色一级片| 亚洲激情自拍| 亚洲人在线视频| 久久一本综合频道| 久久国产欧美精品| 国产精品一区视频网站| 一本色道久久| 一本色道久久加勒比精品| 久久伊伊香蕉| 久久亚洲精品欧美| 国产日韩在线视频| 亚洲一区在线观看视频| 亚洲一区二区三区免费在线观看| 六十路精品视频| 美国十次了思思久久精品导航| 国产精品夜色7777狼人| 亚洲综合国产| 久久精品国产2020观看福利| 国产精品二区在线| 亚洲一区二区免费| 午夜亚洲激情| 国产偷国产偷精品高清尤物| 亚洲天堂激情| 欧美一区二区在线| 国产日产精品一区二区三区四区的观看方式 | 国产亚洲欧美另类中文| 亚洲欧美一区二区三区极速播放| 亚洲主播在线| 国产欧美精品va在线观看| 亚洲一区二区视频| 久久精品国内一区二区三区| 国产亚洲激情视频在线| 久久久亚洲欧洲日产国码αv| 老司机精品视频一区二区三区| 狠狠色综合播放一区二区| 久久夜色精品| 亚洲精选国产| 欧美一区二区日韩一区二区| 国产中文一区二区| 免费欧美日韩| 这里只有精品视频| 久久久久久久性| 亚洲电影免费观看高清完整版在线| 免费观看一区| 亚洲视频第一页| 裸体女人亚洲精品一区| 亚洲人成亚洲人成在线观看图片 | 国产精品国产亚洲精品看不卡15| 亚洲欧美激情诱惑| 欧美激情在线观看| 亚洲一区欧美激情| 国模精品一区二区三区| 欧美精品亚洲二区| 午夜亚洲福利| 亚洲精品国产视频| 欧美伊人久久久久久久久影院| 伊人色综合久久天天| 欧美日韩不卡一区| 久久国产精品亚洲77777| 91久久精品一区二区三区| 先锋影音久久久| 亚洲精品少妇| 狠狠色狠狠色综合系列| 欧美日韩国产一区二区三区地区| 国产精品99久久久久久有的能看| 久久综合国产精品| 亚洲影视在线| 亚洲看片一区| 精品1区2区3区4区| 国产精品日韩一区| 欧美激情网友自拍| 久久免费视频在线观看| 亚洲香蕉伊综合在人在线视看| 欧美mv日韩mv国产网站| 欧美一区二区三区久久精品茉莉花| 亚洲肉体裸体xxxx137| 国产一区在线看| 国产精品日韩电影| 欧美日韩一区二区三区四区在线观看 | 欧美一区二区三区免费视频| 99热这里只有成人精品国产| 亚洲成色www8888| 久久夜色精品国产亚洲aⅴ | 在线日韩av片| 国产日韩视频| 国产精品素人视频| 欧美日韩国产天堂| 欧美精品九九99久久| 久久在线免费观看| 久久九九精品| 欧美有码视频| 欧美在线免费观看| 欧美一级片在线播放| 午夜精品999| 亚洲欧美日韩一区二区在线 | 夜久久久久久| 夜夜躁日日躁狠狠久久88av| 亚洲人成人一区二区在线观看| 欧美成人精品福利| 老司机一区二区| 另类图片国产| 亚洲高清电影| 亚洲人成人77777线观看| 亚洲国产精品一区二区第一页| 欧美激情成人在线视频| 亚洲二区在线观看| 亚洲欧洲日产国产网站| 亚洲精品中文字幕女同| 一本大道久久精品懂色aⅴ| 99人久久精品视频最新地址| 一区二区三区四区五区在线| 亚洲一区成人| 欧美一区二区网站| 久久久久久久尹人综合网亚洲| 久久影院午夜论| 欧美激情国产日韩精品一区18| 欧美精品 国产精品| 欧美午夜剧场| 国产欧美亚洲一区| 亚洲第一页中文字幕| 亚洲日本欧美天堂| 亚洲男女毛片无遮挡| 久久久精品日韩欧美| 亚洲丶国产丶欧美一区二区三区| 亚洲国产精品热久久| 亚洲视频狠狠| 久久国产精彩视频| 欧美福利视频网站| 国产精品国产三级国产普通话三级 | 亚洲视频在线看| 久久精品国产视频| 亚洲第一成人在线| 亚洲综合二区| 欧美高清在线视频| 国产日韩欧美夫妻视频在线观看| 在线看欧美日韩| 亚洲欧美日韩电影| 欧美成人一区二区在线| 一区二区三区黄色| 美女主播视频一区| 国产美女精品视频| 99国产精品国产精品久久| 欧美在线视频二区| 亚洲日本电影在线| 久久大逼视频| 欧美日韩中字| 91久久线看在观草草青青| 午夜视频在线观看一区二区| 亚洲第一精品久久忘忧草社区| 亚洲欧美激情视频| 欧美日韩亚洲不卡| 亚洲人成亚洲人成在线观看图片| 欧美一级在线视频|