• <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>

            OpenGL打印&&預(yù)覽

            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 閱讀(2656) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久精品国产欧美日韩| 青青热久久国产久精品 | 99久久人妻无码精品系列| 人妻少妇久久中文字幕| 久久综合久久久| 亚洲精品WWW久久久久久| 久久久精品人妻一区二区三区四| 99久久精品毛片免费播放| 久久久久无码中| 久久精品国产99国产精偷| 色妞色综合久久夜夜| av国内精品久久久久影院| 伊色综合久久之综合久久| 久久国产精品久久久| 色播久久人人爽人人爽人人片AV| 品成人欧美大片久久国产欧美...| 国产免费久久精品99re丫y| 久久av高潮av无码av喷吹| 久久精品亚洲一区二区三区浴池| 久久综合久久伊人| 精品国产一区二区三区久久蜜臀 | 天天久久狠狠色综合| 亚洲国产精品无码久久SM| 久久精品国产精品亚洲艾草网美妙| 久久夜色精品国产噜噜噜亚洲AV| 香蕉99久久国产综合精品宅男自 | 91超碰碰碰碰久久久久久综合| 无码人妻少妇久久中文字幕蜜桃 | 久久91综合国产91久久精品| 亚洲AV无一区二区三区久久 | 亚洲精品tv久久久久久久久| 精品久久久久成人码免费动漫| 久久综合色之久久综合| 久久精品国产只有精品66| 国内精品伊人久久久久网站| 久久久精品国产Sm最大网站| 久久久久亚洲AV无码专区网站| 日韩影院久久| 亚洲?V乱码久久精品蜜桃| 国产精品久久久久久五月尺| 国产亚洲精品久久久久秋霞|