diff --git a/src/Aspect/Aspect.cdl b/src/Aspect/Aspect.cdl index 10a489fb6f..3b5bc46786 100755 --- a/src/Aspect/Aspect.cdl +++ b/src/Aspect/Aspect.cdl @@ -844,6 +844,29 @@ is end TypeOfColorScaleOrientation; ---Purpose: Defines the type of color scale orientation + enumeration PrintAlgo is + PA_STRETCH, + PA_TILE + end PrintAlgo; + ---Purpose: Defines print algorithm + -- Aspect_PrintAlgo: + -- 1) PA_STRETCH - Stretch offscreen printing frame + -- if its dimensions are smaller than + -- the printer's printing area dimensions; + -- This algorithm is more reliable as it + -- works on any hardware and is recommended + -- to be used with average printing resolutions, + -- as it more RAM memory dependent than PA_TILE; + -- Stretching is performend using bicubic interpolation + -- algorithm from FreeImage library if OCCT is built + -- with FreeImage support, otherwise Windows API + -- StretchBlt() function in STRETCH_HALFTONE mode + -- is used; + -- 2) PA_TILE - If the offscreen printing frame dimensions + -- are smaller than the printer's printing + -- area dimensions - use multiple printing + -- frames to cover the whole printing area + --------------------------------- -- Category: Instantiated classes --------------------------------- diff --git a/src/Graphic3d/Graphic3d_GraphicDriver.cdl b/src/Graphic3d/Graphic3d_GraphicDriver.cdl index 3f6c369283..6bc9d05e15 100755 --- a/src/Graphic3d/Graphic3d_GraphicDriver.cdl +++ b/src/Graphic3d/Graphic3d_GraphicDriver.cdl @@ -66,6 +66,7 @@ uses TypeOfTriedronPosition from Aspect, Handle from Aspect, Display from Aspect, + PrintAlgo from Aspect, AspectLine3d from Graphic3d, AspectMarker3d from Graphic3d, @@ -1300,8 +1301,10 @@ is ACOverLayer : CLayer2d from Aspect; hPrnDC : Handle from Aspect; showBackground : Boolean; - filename : CString) - is deferred; + filename : CString; + printAlgorithm : PrintAlgo from Aspect = Aspect_PA_STRETCH; + theScaleFactor : Real from Standard = 1.0 ) + returns Boolean from Standard is deferred; ---Level: Internal ---Purpose: print the contents of all layers of the view to the printer. -- : Pass the PrinterDeviceContext (HDC), @@ -1309,6 +1312,13 @@ is -- (background is white) -- else set to TRUE for printing with current background color. -- : If != NULL, then the view will be printed to a file. + -- : Select print algorithm: stretch, tile. + -- : Scaling coefficient, used internally to scale the + -- printings accordingly to the scale factor selected in the printer + -- properties dialog. + -- Returns Standard_True if the data is passed to the printer, otherwise + -- Standard_False if the print operation failed due to the printer errors, + -- or insufficient system memory available. ---Warning: Works only under Windows. diff --git a/src/Graphic3d/Graphic3d_GraphicDriver_Print.cxx b/src/Graphic3d/Graphic3d_GraphicDriver_Print.cxx index 0ee4d5dce5..ddc2075494 100755 --- a/src/Graphic3d/Graphic3d_GraphicDriver_Print.cxx +++ b/src/Graphic3d/Graphic3d_GraphicDriver_Print.cxx @@ -14,10 +14,14 @@ /* Print Methods */ /************************************************************************/ -void Graphic3d_GraphicDriver::Print (const Graphic3d_CView& , - const Aspect_CLayer2d& , - const Aspect_CLayer2d& , - const Aspect_Handle , - const Standard_Boolean , - const Standard_CString ) const { - } +Standard_Boolean Graphic3d_GraphicDriver::Print (const Graphic3d_CView& , + const Aspect_CLayer2d& , + const Aspect_CLayer2d& , + const Aspect_Handle , + const Standard_Boolean , + const Standard_CString , + const Aspect_PrintAlgo , + const Standard_Real ) const +{ + return Standard_False; +} diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index 8dcd730537..fbbb96b21c 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -247,3 +247,5 @@ OpenGl_ResourceVBO.cxx OpenGl_ResourceVBO.hxx OpenGl_ResourceTexture.cxx OpenGl_ResourceTexture.hxx +OpenGl_PrinterContext.cxx +OpenGl_PrinterContext.hxx diff --git a/src/OpenGl/OpenGl_GraphicDriver.cdl b/src/OpenGl/OpenGl_GraphicDriver.cdl index 19af1a5afe..9f59be9d22 100755 --- a/src/OpenGl/OpenGl_GraphicDriver.cdl +++ b/src/OpenGl/OpenGl_GraphicDriver.cdl @@ -49,6 +49,7 @@ uses TypeOfTriedronPosition from Aspect, Handle from Aspect, Display from Aspect, + PrintAlgo from Aspect, AspectLine3d from Graphic3d, AspectMarker3d from Graphic3d, @@ -1208,8 +1209,10 @@ is ACOverLayer : CLayer2d from Aspect; hPrnDC : Handle from Aspect; showBackground : Boolean; - filename : CString) - is redefined static; + filename : CString; + printAlgorithm : PrintAlgo from Aspect = Aspect_PA_STRETCH; + theScaleFactor : Real from Standard = 1.0 ) + returns Boolean from Standard is redefined static; ---Level: Internal ---Purpose: print the contents of all layers of the view to the printer. -- : Pass the PrinterDeviceContext (HDC), @@ -1217,6 +1220,17 @@ is -- (background is white) -- else set to TRUE for printing with current background color. -- : If != NULL, then the view will be printed to a file. + -- : Select print algorithm: stretch, tile. + -- : Scaling coefficient, used internally to scale the + -- printings accordingly to the scale factor selected in the printer + -- properties dialog. + -- Returns Standard_True if the data is passed to the printer, otherwise + -- Standard_False if the print operation failed due to the printer errors, + -- or lack of system memory. This might be related to insufficient memory + -- or some internal errors. All this errors are indicated by the message + -- boxes (on level of OpenGl_GraphicDriver). + -- Warning: This function can reuse FBO assigned to the view + -- Please take it into account if you use it for your purposes; ---Warning: Works only under Windows. diff --git a/src/OpenGl/OpenGl_GraphicDriver_print.cxx b/src/OpenGl/OpenGl_GraphicDriver_print.cxx index 05d1cdab16..ef1646a603 100755 --- a/src/OpenGl/OpenGl_GraphicDriver_print.cxx +++ b/src/OpenGl/OpenGl_GraphicDriver_print.cxx @@ -18,12 +18,15 @@ /* Print Methods */ /************************************************************************/ -void OpenGl_GraphicDriver::Print (const Graphic3d_CView& ACView, - const Aspect_CLayer2d& ACUnderLayer, - const Aspect_CLayer2d& ACOverLayer, - const Aspect_Handle hPrintDC, - const Standard_Boolean showBackground, - const Standard_CString filename ) const +Standard_Boolean OpenGl_GraphicDriver::Print + (const Graphic3d_CView& ACView, + const Aspect_CLayer2d& ACUnderLayer, + const Aspect_CLayer2d& ACOverLayer, + const Aspect_Handle hPrintDC, + const Standard_Boolean showBackground, + const Standard_CString filename, + const Aspect_PrintAlgo printAlgorithm, + const Standard_Real theScaleFactor) const { #ifdef WNT @@ -35,11 +38,12 @@ void OpenGl_GraphicDriver::Print (const Graphic3d_CView& ACView, PrintFunction ("call_togl_print"); PrintCView (MyCView, 1); } - call_togl_print (&MyCView, &MyCUnderLayer, &MyCOverLayer, - hPrintDC, (int)showBackground, filename); + return call_togl_print (&MyCView, &MyCUnderLayer, &MyCOverLayer, + hPrintDC, (int)showBackground, filename, + (int)printAlgorithm, (float)theScaleFactor); #else Standard_NotImplemented::Raise ("OpenGl_GraphicDriver::Print is implemented " "only on Windows"); - + return Standard_False; #endif } diff --git a/src/OpenGl/OpenGl_PrinterContext.cxx b/src/OpenGl/OpenGl_PrinterContext.cxx new file mode 100644 index 0000000000..4e3d4b2a9c --- /dev/null +++ b/src/OpenGl/OpenGl_PrinterContext.cxx @@ -0,0 +1,110 @@ +// File: OpenGl_PrinterContext.cxx +// Created: 20.05.11 10:00:00 +// Author: Anton POLETAEV + +#include + +OpenGl_PrinterContext* OpenGl_PrinterContext::g_PrinterContext = NULL; +GLCONTEXT OpenGl_PrinterContext::g_ContextId = NULL; + +//======================================================================= +//function : OpenGl_PrinterContext +//purpose : Constructor +//======================================================================= + +OpenGl_PrinterContext::OpenGl_PrinterContext (GLCONTEXT theCtx) : + myCtx (theCtx), myProjTransform (0, 3, 0, 3), myLayerViewportX (0), + myLayerViewportY (0), myScaleX (1.0f), myScaleY (1.0f) +{ + // assign global instance to the current object + if (myCtx != NULL) + { + g_PrinterContext = this; + g_ContextId = myCtx; + } + + // init projection matrix + Standard_Real anInitValue = 0.0; + myProjTransform.Init (anInitValue); + myProjTransform (0,0) = 1.0f; + myProjTransform (1,1) = 1.0f; + myProjTransform (2,2) = 1.0f; + myProjTransform (3,3) = 1.0f; +} + +//======================================================================= +//function : ~OpenGl_PrinterContext +//purpose : Destructor +//======================================================================= + +OpenGl_PrinterContext::~OpenGl_PrinterContext () +{ + // unassign global instance + if (g_PrinterContext == this) + { + g_ContextId = NULL; + g_PrinterContext = NULL; + } +} + +//======================================================================= +//function : GetProjTransformation +//purpose : Get view projection transformation matrix. +//======================================================================= + +void OpenGl_PrinterContext::GetProjTransformation (GLfloat theMatrix[16]) +{ + for (int i = 0, k = 0; i < 4; i++) + for (int j = 0; j < 4; j++, k++) + theMatrix[k] = (GLfloat)myProjTransform (i,j); +} + +//======================================================================= +//function : SetProjTransformation +//purpose : Set view projection transformation matrix for printing purposes. +// theProjTransform parameter should be an 4x4 array. +//======================================================================= + +bool OpenGl_PrinterContext::SetProjTransformation (TColStd_Array2OfReal& thePrj) +{ + if (thePrj.RowLength () != 4 || thePrj.ColLength () != 4) + return false; + + myProjTransform = thePrj; + + return true; +} + +//======================================================================= +//function : Deactivate +//purpose : Deactivate PrinterContext object. +// Useful when you need to redraw in usual mode the same +// OpenGl context that you used for printing right after printing, +// before the OpenGl_PrinterContext instance destroyed +//======================================================================= + +void OpenGl_PrinterContext::Deactivate () +{ + // unassign global instance + if (g_PrinterContext == this) + { + g_ContextId = NULL; + g_PrinterContext = NULL; + } +} + + +//======================================================================= +//function : GetInstance +//purpose : Get the PrinterContext instance assigned for OpenGl context. +// Return NULL, if there is no current printing operation and +// there is no assigned instance for "theCtx" OpenGl context. +//======================================================================= + +OpenGl_PrinterContext* OpenGl_PrinterContext::GetPrinterContext (GLCONTEXT theCtx) +{ + if (g_ContextId == theCtx) + return g_PrinterContext; + else + return NULL; +} diff --git a/src/OpenGl/OpenGl_PrinterContext.hxx b/src/OpenGl/OpenGl_PrinterContext.hxx new file mode 100644 index 0000000000..2f117fd164 --- /dev/null +++ b/src/OpenGl/OpenGl_PrinterContext.hxx @@ -0,0 +1,116 @@ +// File: OpenGl_PrinterContext.hxx +// Created: 20.05.11 10:00:00 +// Author: Anton POLETAEV + +#ifndef _OPENGL_PRINTERCONTEXT_H +#define _OPENGL_PRINTERCONTEXT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Standard_Transient; +class Handle(Standard_Type); +class Handle(MMgt_TShared); +class OpenGl_PrinterContext; + +DEFINE_STANDARD_HANDLE(OpenGl_PrinterContext,MMgt_TShared) + +//! Class provides specific information for redrawing view to offscreen buffer +//! on printing. The information is: projection matrixes for tiling, +//! scaling factors for text/markers and layer viewport dimensions. +//! The OpenGl_PrinterContext class allows to have only one global instance +//! that can be accessed by GetPrinterContext() during printing operation. +//! The class instance can be created only by call_togl_print(). +class OpenGl_PrinterContext : public MMgt_TShared +{ + +public: + + //! Get the PrinterContext instance assigned for OpenGl context. + //! Return NULL, if there is no current printing operation and + //! there is no assigned instance for "theCtx" OpenGl context. + static OpenGl_PrinterContext* GetPrinterContext(GLCONTEXT theCtx); + + //! Get view projection transformation matrix. + const TColStd_Array2OfReal& GetProjTransformation () + { + return myProjTransform; + } + + //! Get view projection transformation matrix. + void GetProjTransformation (GLfloat theMatrix[16]); + + //! Get text/markers scale factor + void GetScale (GLfloat& theScaleX, GLfloat& theScaleY) + { + theScaleX = myScaleX; + theScaleY = myScaleY; + } + + //! Get layer viewport dimensions + void GetLayerViewport (GLsizei& theViewportX, + GLsizei& theViewportY) + { + theViewportX = myLayerViewportX; + theViewportY = myLayerViewportY; + } + +private: + + //! Constructor + OpenGl_PrinterContext (GLCONTEXT theCtx); + + //! Destructor + virtual ~OpenGl_PrinterContext (); + + //! Deactivate current printing context. + //! Useful when you need to redraw in usual mode the same OpenGl context + //! that you used for printing right after printing, before the + //! OpenGl_PrinterContext instance destroyed. + void Deactivate (); + + //! Set view projection transformation matrix for printing/tiling purposes + //! theProjTransform parameter should be an 4x4 array. + bool SetProjTransformation (TColStd_Array2OfReal& theProjTransform); + + //! Set text scale factor + void SetScale (GLfloat theScaleX, GLfloat theScaleY) + { + myScaleX = theScaleX; + myScaleY = theScaleY; + } + + //! Set layer viewport dimensions + void SetLayerViewport (GLsizei theViewportX, + GLsizei theViewportY) + { + myLayerViewportX = theViewportX; + myLayerViewportY = theViewportY; + } + +private: + + static OpenGl_PrinterContext* g_PrinterContext; + static GLCONTEXT g_ContextId; + TColStd_Array2OfReal myProjTransform; + GLfloat myScaleX; + GLfloat myScaleY; + GLsizei myLayerViewportX; + GLsizei myLayerViewportY; + GLCONTEXT myCtx; + + // the printer context could be created only in method call_togl_print + friend Standard_Boolean call_togl_print (CALL_DEF_VIEW *, CALL_DEF_LAYER *, + CALL_DEF_LAYER *, + const Aspect_Drawable, const int, + const char*, const int, const float); +}; + +#endif diff --git a/src/OpenGl/OpenGl_TextRender.cxx b/src/OpenGl/OpenGl_TextRender.cxx index e0d9a93372..147ae52f2a 100755 --- a/src/OpenGl/OpenGl_TextRender.cxx +++ b/src/OpenGl/OpenGl_TextRender.cxx @@ -4,16 +4,16 @@ #include #include -#include -#include - -#include - +#include #include #include #include #include #include +#include +#include +#include +#include #include #include @@ -384,6 +384,22 @@ void OpenGl_TextRender::RenderText ( const wchar_t* str, GLuint base, int is2d, if( ! zoom ) { +#ifdef WNT + // if the context has assigned printer context, use it's parameters + OpenGl_PrinterContext* aPrinterContext = + OpenGl_PrinterContext::GetPrinterContext( GET_GL_CONTEXT() ); + if( aPrinterContext ) + { + // get printing scaling in x and y dimensions + GLfloat aTextScalex = 1, aTextScaley = 1; + aPrinterContext->GetScale( aTextScalex, aTextScaley ); + + // text should be scaled in all directions with same + // factor to save its proportions, so use height (y) scaling + // as it is better for keeping text/3d graphics proportions + glScalef( aTextScaley, aTextScaley, aTextScaley ); + } +#endif glScaled( h, h, h ); } else diff --git a/src/OpenGl/OpenGl_tgl_funcs.hxx b/src/OpenGl/OpenGl_tgl_funcs.hxx index a4d3e6d5b5..5b4fad7a25 100755 --- a/src/OpenGl/OpenGl_tgl_funcs.hxx +++ b/src/OpenGl/OpenGl_tgl_funcs.hxx @@ -1334,16 +1334,18 @@ void EXPORT call_togl_userdraw ( ); /* ------------------------- */ -void EXPORT call_togl_print ( +Standard_Boolean EXPORT call_togl_print ( - CALL_DEF_VIEW *aview, - CALL_DEF_LAYER *anunderlayer, - CALL_DEF_LAYER *anoverlayer, - const Aspect_Drawable hPrintDC, - const int background, - const char* filename + CALL_DEF_VIEW *aview, + CALL_DEF_LAYER *anunderlayer, + CALL_DEF_LAYER *anoverlayer, + const Aspect_Drawable hPrintDC, + const int background, + const char* filename, + const int printalgo = 0, + const float theScaleFactor = 1.0 - ); + ); #ifdef BUC61044 diff --git a/src/OpenGl/OpenGl_togl_begin_layer_mode.cxx b/src/OpenGl/OpenGl_togl_begin_layer_mode.cxx index 7213a57d15..5729b1edd0 100755 --- a/src/OpenGl/OpenGl_togl_begin_layer_mode.cxx +++ b/src/OpenGl/OpenGl_togl_begin_layer_mode.cxx @@ -57,6 +57,7 @@ HISTORIQUE DES MODIFICATIONS : #include #include +#include /*----------------------------------------------------------------------*/ /* @@ -297,6 +298,35 @@ call_togl_redraw_layer2d ( printf ("\tratio %f new ortho %f %f %f %f\n", ratio, left, right, bottom, top); #endif + +#ifdef WNT + // Check printer context that exists only for print operation + OpenGl_PrinterContext* aPrinterContext = + OpenGl_PrinterContext::GetPrinterContext (GET_GL_CONTEXT()); + + if (aPrinterContext) + { + // additional transformation matrix could be applied to + // render only those parts of viewport that will be + // passed to a printer as a current "frame" to provide + // tiling; scaling of graphics by matrix helps render a + // part of a view (frame) in same viewport, but with higher + // resolution + GLfloat aProjMatrix[16]; + aPrinterContext->GetProjTransformation (aProjMatrix); + glLoadMatrixf ((GLfloat*) aProjMatrix); + + // printing operation also assumes other viewport dimension + // to comply with transformation matrix or graphics scaling + // factors for tiling for layer redraw + GLsizei anViewportX = 0; + GLsizei anViewportY = 0; + aPrinterContext->GetLayerViewport (anViewportX, anViewportY); + if (anViewportX != 0 && anViewportY != 0) + glViewport (0, 0, anViewportX, anViewportY); + } +#endif + glOrtho (left, right, bottom, top, -1.0, 1.0); #ifdef TRACE_MAT diff --git a/src/OpenGl/OpenGl_togl_print.cxx b/src/OpenGl/OpenGl_togl_print.cxx index ed55b8febd..d5b580b60b 100755 --- a/src/OpenGl/OpenGl_togl_print.cxx +++ b/src/OpenGl/OpenGl_togl_print.cxx @@ -17,85 +17,315 @@ e-mail t-hartl@muenchen.matra-dtv.fr */ #include #include #include - +#include +#include +#include +#include #include -/* SAV - begin */ -/* MSDN says: point is 1/72 inch. But in our case text height in the 3D view -differs from printed one. An experiment showed that delimeter equal to 2*72 gives -practically equal text heights. */ -int defaultDelimeter = 72; -int delimeter = 144; -int defaultPntSize = 12; - -GLuint printerFontBase = 0; - -/* printer DC needed to avoid passing OS specific type as a procedure parameter */ -#ifdef WNT -HDC printer; -HGDIOBJ oldObj; +#ifdef HAVE_FREEIMAGE + #include + #include + #ifdef _MSC_VER + #pragma comment( lib, "FreeImage.lib" ) + #pragma comment( lib, "FreeImagePlus.lib" ) + #endif + typedef NCollection_Handle FipHandle; #endif -GLuint createFont( char* typeFace, int height, int weight, int italic ) +// --------------------------------------------------------------- +// Function: getNearestPowOfTwo +// Purpose: get the nearest power of two for theNumber +// --------------------------------------------------------------- +static GLsizei getNearestPowOfTwo (const GLsizei theNumber) { -#ifdef WNT - /* no unicode support yet*/ - HFONT font; - GLuint base; - DWORD charSet = ANSI_CHARSET; - - if ( ( base = glGenLists( 96 ) ) == 0 ) - return 0; - - if ( _stricmp( typeFace, "symbol" ) == 0 ) - charSet = SYMBOL_CHARSET; - - font = CreateFont( height, 0, 0, 0, weight, italic, FALSE, FALSE, - charSet, OUT_TT_PRECIS, - CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, - DEFAULT_PITCH, typeFace ); - oldObj = SelectObject( printer, font ); - wglUseFontBitmaps( printer, 32, 96, base ); - return base; -#endif - return 0; + GLsizei aLast = 1; + for (GLsizei p2 = 1; p2 <= theNumber; aLast = p2, p2 <<= 1); + return aLast; } -void deleteFont( GLuint base ) +// --------------------------------------------------------------- +// Function: getMaxFrameSize +// Purpose: get the maximum possible frame size +// --------------------------------------------------------------- +static void getMaxFrameSize(Standard_Integer& theWidth, + Standard_Integer& theHeight) { -#ifdef WNT - HFONT currentFont; + GLsizei aMaxX, aMaxY; + GLint aVpDim[2]; + GLint aTexDim = 2048; + glGetIntegerv (GL_MAX_VIEWPORT_DIMS, (GLint*) &aVpDim); + glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aTexDim); + (aVpDim[0] >= aTexDim) ? aMaxX = (GLsizei) aTexDim : + aMaxX = getNearestPowOfTwo((GLsizei)aVpDim[0]); + (aVpDim[1] >= aTexDim) ? aMaxY = (GLsizei) aTexDim : + aMaxY = getNearestPowOfTwo((GLsizei)aVpDim[1]); - if ( base == 0 ) - /* no font created */ - return; - /* deleting font list id */ - glDeleteLists( base, 96 ); - currentFont = (HFONT)SelectObject( printer, oldObj ); - /* deleting current font structure */ - DeleteObject( currentFont ); -#endif + theWidth = (Standard_Integer)aMaxX; + theHeight = (Standard_Integer)aMaxY; } -void updatePrinterFont( char* type, int height ) +// --------------------------------------------------------------- +// Function: fitDimensionsRatio +// Purpose: calculate correct width/height ratio for theWidth and +// theHeight parameters +// --------------------------------------------------------------- +static void fitDimensionsRatio (Standard_Integer& theWidth, + Standard_Integer& theHeight, + const Standard_Real theViewRatio) { -#ifdef WNT - int delim = delimeter; - if ( height <= 0 ) { - height = defaultPntSize; - delim = defaultDelimeter; + // set dimensions in accordance with the viewratio + if (theHeight < theWidth/theViewRatio) + theWidth = (Standard_Integer)(theHeight*theViewRatio); + + if (theWidth < theHeight*theViewRatio) + theHeight = (Standard_Integer)(theWidth/theViewRatio); +} + +// --------------------------------------------------------------- +// Function: getDimensionsTiling +// Purpose: calculate maximum possible dimensions for framebuffer +// in tiling mode according to the view size +// --------------------------------------------------------------- +static void getDimensionsTiling (Standard_Integer& theFrameWidth, + Standard_Integer& theFrameHeight, + const int theViewWidth, + const int theViewHeight) +{ + // fit the maximum dimensions into the printing area + if (theFrameWidth > theViewWidth) + theFrameWidth = theViewWidth; + + if (theFrameHeight > theViewHeight) + theFrameHeight = theViewHeight; +} + +// --------------------------------------------------------------- +// Function: initBufferStretch +// Purpose: calculate initialization sizes for frame buffer +// when the stretch algorithm is selected +// --------------------------------------------------------------- +static void initBufferStretch (Standard_Integer& theFrameWidth, + Standard_Integer& theFrameHeight, + const int theViewWidth, + const int theViewHeight) +{ + + // Calculate correct width/height for framebuffer + Standard_Real aViewRatio = (Standard_Real)theViewWidth/theViewHeight; + fitDimensionsRatio (theFrameWidth, theFrameHeight, aViewRatio); + + // downscale the framebuffer if it is too large + Standard_Real aWidthRate = (Standard_Real)theFrameWidth /theViewWidth; + Standard_Real aHeightRate = (Standard_Real)theFrameHeight/theViewHeight; + + if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate >= aHeightRate) || + (aWidthRate > 1 && aHeightRate <= 1)) + { + theFrameWidth = (Standard_Integer)(theFrameWidth /aWidthRate); + theFrameHeight = (Standard_Integer)(theFrameHeight/aWidthRate); } - /* deleting old font */ - deleteFont( printerFontBase ); - /* creating new one */ - printerFontBase = createFont( type, -MulDiv( height, GetDeviceCaps( printer, LOGPIXELSY ), delim ), - (int)FW_NORMAL, 0 ); -#endif + else if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate < aHeightRate) || + (aWidthRate <= 1 && aHeightRate > 1)) + { + theFrameWidth = (Standard_Integer)(theFrameWidth /aHeightRate); + theFrameHeight = (Standard_Integer)(theFrameHeight/aHeightRate); + } + } -/* SAV - end */ + +// --------------------------------------------------------------- +// Function: initBufferTiling +// Purpose: calculate initialization sizes for frame buffer +// when the tile algorithm is selected +// --------------------------------------------------------------- +static void initBufferTiling (Standard_Integer& theFrameWidth, + Standard_Integer &theFrameHeight, + const int theViewWidth, + const int theViewHeight) +{ + // fit framebuffer into the printing area + if (theFrameWidth > theViewWidth) + theFrameWidth = theViewWidth; + + if (theFrameHeight > theViewHeight) + theFrameHeight = theViewHeight; +} + +// --------------------------------------------------------------- +// Function: redrawView +// Purpose: redraw view in printing mode +// --------------------------------------------------------------- +static void redrawView (CALL_DEF_VIEW *aview, + CALL_DEF_LAYER *anunderlayer, + CALL_DEF_LAYER *anoverlayer, + const int isBackground) +{ + // prepare for redraw + call_func_redraw_all_structs_begin (aview->WsId); + call_togl_setplane (aview); + + // clear background + if (isBackground == 0) + { + glClearColor (1.0, 1.0, 1.0, 1.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + // draw underlayer + if (anunderlayer->ptrLayer) + { + call_togl_redraw_layer2d (aview, anunderlayer); + } + + // redraw main plane + call_func_redraw_all_structs_proc (aview->WsId); + call_subr_displayCB (aview,OCC_REDRAW_BITMAP | OCC_PRE_OVERLAY); + // draw overlayer + if (anoverlayer->ptrLayer) + { + call_togl_redraw_layer2d (aview, anoverlayer); + } + call_subr_displayCB (aview,OCC_REDRAW_BITMAP); -void EXPORT + // tell to end redrawing + call_func_redraw_all_structs_end (aview->WsId, 0); + call_togl_redraw_immediat_mode (aview); +} + +// --------------------------------------------------------------- +// Function: initBitmapBuffer +// Purpose: init device independent bitmap to hold printing data +// --------------------------------------------------------------- +#ifdef WNT +#ifndef HAVE_FREEIMAGE +static void initBitmapBuffer (const HDC theMemoryDC, + HBITMAP &theMemoryBmp, + const Standard_Integer theBmpWidth, + const Standard_Integer theBmpHeight, + VOID* &theBufferPtr) +{ + // define compatible bitmap + BITMAPINFO aBitmapData; + memset (&aBitmapData, 0, sizeof (BITMAPINFOHEADER)); + aBitmapData.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + aBitmapData.bmiHeader.biWidth = theBmpWidth; + aBitmapData.bmiHeader.biHeight = theBmpHeight; + aBitmapData.bmiHeader.biPlanes = 1; + aBitmapData.bmiHeader.biBitCount = 24; + aBitmapData.bmiHeader.biXPelsPerMeter = 0; + aBitmapData.bmiHeader.biYPelsPerMeter = 0; + aBitmapData.bmiHeader.biClrUsed = 0; + aBitmapData.bmiHeader.biClrImportant = 0; + aBitmapData.bmiHeader.biCompression = BI_RGB; + aBitmapData.bmiHeader.biSizeImage = 0; + + // Create Device Independent Bitmap + theMemoryBmp = CreateDIBSection (theMemoryDC, &aBitmapData, DIB_RGB_COLORS, + &theBufferPtr, NULL, 0); +} +#else +// --------------------------------------------------------------- +// Function: imagePasteDC +// Purpose: copy the data from image buffer to the device context +// --------------------------------------------------------------- +static bool imagePasteDC(HDC theDstDC, FipHandle theImage, int theOffsetX, + int theOffsetY, int theWidth, int theHeight, + int theLeft = 0, int theTop = 0) +{ + // get image parameters + BITMAPINFO* aBitmapData = theImage->getInfo (); + SetStretchBltMode (theDstDC, STRETCH_HALFTONE); + + // organize blocks data passing if memory isn't enough to pass all the data + // at once + int aLinesComplete = 0, aMaxBlockWidth = theHeight, aBlockWidth = 0, + aPassed = 0, aInverseLine = 0, aScan = 0; + BYTE *aDataPtr = 0; + while (aMaxBlockWidth >= 1 && aLinesComplete < theHeight) + { + // how much lines still to pass + aBlockWidth = theHeight - aLinesComplete; + + // normalize count of lines to pass to maximum lines count at one pass. + if (aBlockWidth > aMaxBlockWidth) + aBlockWidth = aMaxBlockWidth; + + // access image data at the start scan line, we need to calculate scan from + // the bottom of image (image is bottom-left, the src coord is top-left) + aInverseLine = theTop + aBlockWidth + aLinesComplete; + aScan = theImage->getHeight() - aInverseLine; + aDataPtr = theImage->getScanLine (aScan); + if (!aDataPtr) + return false; + + // try to pass block to the device + if (aBlockWidth > 0) + { + // instead of banded output we provide blocked as it isn't always passed + // to printer as it is expected + aPassed = SetDIBitsToDevice (theDstDC, theOffsetX, + theOffsetY + aLinesComplete, + theWidth, aBlockWidth, theLeft, 0, + 0, aBlockWidth, + aDataPtr, aBitmapData, DIB_RGB_COLORS); + + // if result is bad, try to decrease band width + if (aPassed != aBlockWidth) + { + aMaxBlockWidth = aMaxBlockWidth >> 1; + aLinesComplete = 0; + } + else + aLinesComplete += aBlockWidth; + } + } + + // check for total failure + if (aMaxBlockWidth < 1) + return false; + + return true; +} + +// --------------------------------------------------------------- +// Function: imageStretchDC +// Purpose: copy pixels from image to dc by stretching them +// --------------------------------------------------------------- +static bool imageStretchDC(HDC theDstDC, FipHandle theImage, int theOffsetX, + int theOffsetY, int theWidth, int theHeight) +{ + // access to raw image data + BYTE *aDataPtr = theImage->accessPixels (); + if (!aDataPtr) + return false; + + // get image parameters + unsigned int widthPx = theImage->getWidth (); + unsigned int heightPx = theImage->getHeight (); + BITMAPINFO* aBitmapData = theImage->getInfo (); + SetStretchBltMode (theDstDC, STRETCH_HALFTONE); + + // pass lines and check if operation is succesfull + int aPassed = 0; + aPassed = StretchDIBits (theDstDC, theOffsetX, theOffsetY, theWidth, + theHeight, 0, 0, widthPx, heightPx, aDataPtr, + aBitmapData, DIB_RGB_COLORS, SRCCOPY); + + if (aPassed != heightPx) + return false; + + return true; +} +#endif +#endif + +// --------------------------------------------------------------- +// Function: call_togl_print +// Purpose: +// --------------------------------------------------------------- +Standard_Boolean EXPORT call_togl_print ( CALL_DEF_VIEW *aview, @@ -103,295 +333,470 @@ call_togl_print CALL_DEF_LAYER *anoverlayer, const Aspect_Drawable hPrintDC, const int background, - const char* filename + const char* filename, + const int printalgo, + const float theScaleFactor ) { #ifdef WNT - CMN_KEY_DATA data; - Tint swap = 1; /* swap buffers ? yes */ + CMN_KEY_DATA data; + DOCINFO di; + bool IsTiling = (printalgo == 1); + HDC hPrnDC = (HDC) hPrintDC; - - BOOL bRet = FALSE; - HDC hPrnDC; - DOCINFO di; - - hPrnDC = (HDC) hPrintDC; - printer = hPrnDC; - - /* Begin main routine **************************************************************/ TsmGetWSAttri (aview->WsId, WSWindow, &data); - if (TxglWinset (call_thedisplay, (WINDOW) data.ldata) == TSuccess) + if (TxglWinset (call_thedisplay, (WINDOW) data.ldata) != TSuccess) { - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd - 1, // version number - PFD_SUPPORT_OPENGL| - PFD_DRAW_TO_BITMAP, - PFD_TYPE_RGBA, - 0, 0, 0, 0, 0, 0, // color bits ignored - 0, // no alpha buffer - 0, // shift bit ignored - 0, // no accumulation buffer - 0, 0, 0, 0, // accum bits ignored - 32, // 32-bit z-buffer - 0, // no stencil buffer - 0, // no auxiliary buffer - PFD_MAIN_PLANE, // main layer - 0, // reserved - 0, 0, 0 // layer masks ignored - }; - HWND w; - HDC hDC; - HDC hMemDC; - HGLRC hGLRC; - RECT rect; - - BITMAPINFO* pBMI; - BITMAPINFOHEADER* bmHeader; - - BYTE biInfo[sizeof(BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD)]; - HGDIOBJ hBmOld; - HBITMAP hBm; - VOID* base; - - int nIndex; - int bmiSize; - - float viewRatio; - int devWidth; - int devHeight; - int viewWidth; - int viewHeight; - int width; - int height; - float tempWidth; - float tempHeight; - int offsetx = 0; - int offsety = 0; - -#ifdef mydebug - devWidth = 640; - tempWidth = (float) devWidth; - devHeight = 480; - tempHeight = (float) devHeight; -#else - devWidth = GetDeviceCaps(hPrnDC, HORZRES); - tempWidth = (float) devWidth; - devHeight = GetDeviceCaps(hPrnDC, VERTRES); - tempHeight = (float) devHeight; -#endif - GetClientRect((WINDOW) data.ldata, &rect); - viewWidth = rect.right-rect.left; - viewHeight = rect.bottom-rect.top; - - viewRatio = (float) viewWidth/(float) viewHeight; - - // Calculate correct width/height ratio - if (tempHeight < tempWidth/viewRatio) - tempWidth = tempHeight*viewRatio; - if (tempWidth < tempHeight*viewRatio) - tempHeight = tempWidth/viewRatio; - - width = (int) tempWidth; - height = (int) tempHeight; - - // Create virtual window - w = CreateWindow( - "Button", - "", - WS_OVERLAPPEDWINDOW | - WS_CLIPCHILDREN | - WS_CLIPSIBLINGS, - 0, 0, - width, height, - NULL, - NULL, - NULL, - NULL); -#ifdef mydebug - ShowWindow(w, SW_SHOW); -#endif - - hDC = GetDC(w); - if (!hDC) - { - MessageBox(0,"hDC == NULL", "Fehler", MB_OK); - return; - } - - // Initialize Bitmap Information - - pBMI = (BITMAPINFO *) biInfo; - ZeroMemory(pBMI, sizeof(*pBMI)); - bmiSize = sizeof(*pBMI); - - pBMI = (BITMAPINFO *) calloc(1, bmiSize); - bmHeader = &pBMI->bmiHeader; - - bmHeader->biSize = sizeof(*bmHeader); - bmHeader->biWidth = width; - bmHeader->biHeight = height; - bmHeader->biPlanes = 1; /* must be 1 */ - bmHeader->biBitCount = 24; - bmHeader->biXPelsPerMeter = 0; - bmHeader->biYPelsPerMeter = 0; - bmHeader->biClrUsed = 0; /* all are used */ - bmHeader->biClrImportant = 0; /* all are important */ - bmHeader->biCompression = BI_RGB; - bmHeader->biSizeImage = 0; - - // Create Device Independent Bitmap - hMemDC = CreateCompatibleDC(hPrnDC); - hBm = CreateDIBSection(hMemDC, pBMI, DIB_RGB_COLORS, &base, NULL, 0); - hBmOld = SelectObject(hMemDC, hBm); - - // Release Memory - free(pBMI); - // free(bmHeader); - - // further initialization -#ifdef mydebug - pfd.cColorBits = GetDeviceCaps(hDC, BITSPIXEL); - nIndex = ChoosePixelFormat(hDC, &pfd); - if (nIndex == 0) - { - MessageBox(0,"ChoosePixelFormat failed", "Error", MB_OK | MB_ICONSTOP); - goto Error; - } - - - if (!SetPixelFormat(hDC, nIndex, &pfd)) - { - MessageBox(0,"SetPixelFormat failed", "Error", MB_OK | MB_ICONSTOP); - goto Error; - } - - // Create Rendering Context - hGLRC = wglCreateContext(hDC); - - if (hGLRC == NULL) - { - MessageBox(0,"No Rendering Context", "Error", MB_OK | MB_ICONSTOP); - goto Error; - } - wglMakeCurrent(hDC,hGLRC); -#else - pfd.cColorBits = GetDeviceCaps(hMemDC, BITSPIXEL); - nIndex = ChoosePixelFormat(hMemDC, &pfd); - if (nIndex == 0) - { - MessageBox(0,"ChoosePixelFormat failed", "Error", MB_OK | MB_ICONSTOP); - goto Error; - } - - - if (!SetPixelFormat(hMemDC, nIndex, &pfd)) - { - MessageBox(0,"SetPixelFormat failed", "Error", MB_OK | MB_ICONSTOP); - goto Error; - } - - // Create Rendering Context - hGLRC = wglCreateContext(hMemDC); - - if (hGLRC == NULL) - { - MessageBox(0,"No Rendering Context", "Error", MB_OK | MB_ICONSTOP); - goto Error; - } - wglMakeCurrent(hMemDC,hGLRC); -#endif - - /* creating default font */ - printerFontBase = - createFont( "", -MulDiv( defaultPntSize, GetDeviceCaps( hPrnDC, LOGPIXELSY ), defaultDelimeter ), - (int)FW_NORMAL, 0 ); - - // redraw to new Rendering Context - call_func_redraw_all_structs_begin (aview->WsId); - - call_togl_setplane( aview ); /* update clipping planes */ - - if (background == 0) - { - glClearColor(1.0, 1.0, 1.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - if (anunderlayer->ptrLayer) - call_togl_redraw_layer2d (aview, anunderlayer); - call_func_redraw_all_structs_proc (aview->WsId); - - if (anoverlayer->ptrLayer) - call_togl_redraw_layer2d (aview, anoverlayer); -#ifdef RIC120302 - call_subr_displayCB(aview,OCC_REDRAW_BITMAP); -#endif - - call_func_redraw_all_structs_end (aview->WsId, swap); - - call_togl_redraw_immediat_mode (aview); -#ifndef mydebug - /* Start printing of DIB ********************************************************/ - di.cbSize = sizeof(DOCINFO); - di.lpszDocName = "Text"; - di.lpszOutput = filename; - - if (StartDoc(hPrnDC, &di) == SP_ERROR) goto Error; - if (StartPage(hPrnDC) <= 0) goto Error; - - // calculate offset for centered printing - if (width < devWidth) - offsetx = (devWidth - width)/2; - if (height < devHeight) - offsety = (devHeight - height)/2; - - BitBlt(hPrnDC, offsetx, offsety, width, height, hMemDC, 0, 0, SRCCOPY); - - EndPage(hPrnDC); - EndDoc(hPrnDC); - /* releasing created font */ - deleteFont( printerFontBase ); - printerFontBase = 0; - - /* End of printing section ******************************************************/ -#else - Sleep(5000); -#endif - -Error: - /* Clean memory *****************************************************************/ - if(hBm != NULL) - { - SelectObject(hMemDC, hBmOld); - DeleteObject(hBm); - DeleteObject(hBmOld); - } - wglMakeCurrent(NULL, NULL); - if (hGLRC != NULL) - { - wglDeleteContext(hGLRC); - } - if (hMemDC != NULL) - { - DeleteDC(hMemDC); - } - - if (hDC != NULL) - { - ReleaseDC(w, hDC); - } - if (w != NULL) - { - DestroyWindow(w); - } - - /* End of clean memory *****************************************************************/ + MessageBox (NULL, "Print failed: can't setup the view for printing.", + "The operation couldn't be completed.", MB_OK); + return Standard_False; } - /* End main routine ********************************************************************/ - return; -#endif /*WNT*/ + // printer page dimensions + int devWidth = GetDeviceCaps (hPrnDC, HORZRES); + int devHeight = GetDeviceCaps (hPrnDC, VERTRES); + + // if context is actually a memory dc, try to retrieve bitmap dimensions + // (memory dc could be used for testing purposes) + if (GetObjectType (hPrnDC) == OBJ_MEMDC) + { + // memory dc dimensions + BITMAP aBitmapInfo; + HBITMAP aMemoryBitmap = (HBITMAP) GetCurrentObject (hPrnDC, OBJ_BITMAP); + if (aMemoryBitmap) + if (GetObject (aMemoryBitmap, sizeof (BITMAP), &aBitmapInfo)) + { + devWidth = aBitmapInfo.bmWidth; + devHeight = aBitmapInfo.bmHeight; + } + } + + Standard_Integer tempWidth = (Standard_Integer) devWidth; + Standard_Integer tempHeight = (Standard_Integer) devHeight; + + // view dimensions + RECT rect; + GetClientRect((WINDOW) data.ldata, &rect); + int viewWidth = rect.right-rect.left; + int viewHeight = rect.bottom-rect.top; + if (viewWidth == 0 || viewHeight == 0) + { + MessageBox (NULL, "Print failed: can't setup the view for printing.", + "The operation couldn't be completed.", MB_OK); + return Standard_False; + } + + // calculate correct width/height ratio + Standard_Real viewRatio = (Standard_Real)viewWidth/viewHeight; + fitDimensionsRatio(tempWidth, tempHeight, viewRatio); + + // width and height for printing area + int width = (int) (tempWidth * theScaleFactor); + int height = (int) (tempHeight * theScaleFactor); + + // device independent bitmap for the whole view +#ifdef HAVE_FREEIMAGE + FipHandle aViewImage = NULL; + BYTE* aViewBuffer = NULL; +#else + HDC hMemDC = CreateCompatibleDC (hPrnDC); + HBITMAP hViewBitmap = NULL; + HGDIOBJ hViewBitmapOld = NULL; + VOID* aViewBuffer = NULL; +#endif + + // Frame buffer initialization + OpenGl_FrameBuffer* aFrameBuffer = NULL; + OpenGl_FrameBuffer* aPrevBuffer = (OpenGl_FrameBuffer*) aview->ptrFBO; + Standard_Integer aFrameWidth (0), aFrameHeight (0), + aPrevBufferX (0), aPrevBufferY (0); + + // try to use existing frame buffer + if (aPrevBuffer) + { + GLsizei aPrevWidth = aPrevBuffer->GetSizeX(); + GLsizei aPrevHeight = aPrevBuffer->GetSizeY(); + bool isUsable = false; + + // check if its possible to use previous frame buffer + if (!IsTiling && aPrevWidth >= width && aPrevHeight >= height) + { + aFrameWidth = (Standard_Integer) width; + aFrameHeight = (Standard_Integer) height; + isUsable = true; + } + else if (IsTiling) + { + getDimensionsTiling (aFrameWidth, aFrameHeight, width, height); + if (aPrevWidth >= aFrameWidth && aPrevHeight >= aFrameHeight) + isUsable = true; + } + + // if it is enough memory for image paste dc operation + if (isUsable) + { +#ifdef HAVE_FREEIMAGE + // try to allocate fipImage and necessary resources + fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth, + aFrameHeight, 24); + + // if allocated succesfully + if (anImagePtr->isValid()) + { + aViewImage = anImagePtr; + aViewBuffer = aViewImage->accessPixels (); + } + else + delete anImagePtr; + + if (!aViewBuffer) + { + isUsable = false; + aViewBuffer = NULL; + aViewImage = NULL; + } +#else + // try to allocate compatible bitmap and necessary resources + initBitmapBuffer (hMemDC, hViewBitmap, + aFrameWidth, aFrameHeight, aViewBuffer); + if (!aViewBuffer) + { + isUsable = false; + if (hViewBitmap) + DeleteObject (hViewBitmap); + hViewBitmap = NULL; + } + else + hViewBitmapOld = SelectObject (hMemDC, hViewBitmap); +#endif + } + + // use previous frame buffer + if (isUsable) + { + aPrevBufferX = aPrevWidth; + aPrevBufferY = aPrevHeight; + aFrameBuffer = aPrevBuffer; + aFrameBuffer->ChangeViewport (aFrameWidth, aFrameHeight); + } + } + + // if previous buffer cannot be used, try to init a new one + if (!aFrameBuffer) + { + aFrameBuffer = new OpenGl_FrameBuffer(); + + // try to create the framebuffer with the best possible size + Standard_Integer aMaxWidth(0), aMaxHeight(0); + getMaxFrameSize (aMaxWidth, aMaxHeight); + while (aMaxWidth > 1 && aMaxHeight > 1) + { + aFrameWidth = aMaxWidth; + aFrameHeight = aMaxHeight; + + // calculate dimensions for different printing algorithms + if (!IsTiling) + initBufferStretch (aFrameWidth, aFrameHeight, width, height); + else + initBufferTiling (aFrameWidth, aFrameHeight, width, height); + + // try to initialize framebuffer + if (aFrameBuffer->Init (aFrameWidth, aFrameHeight)) + { +#ifdef HAVE_FREEIMAGE + // try to allocate fipImage and necessary resources + fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth, + aFrameHeight, 24); + + // if allocated succesfully + if (anImagePtr->isValid()) + { + aViewImage = anImagePtr; + aViewBuffer = aViewImage->accessPixels (); + } + else + delete anImagePtr; + + if (!aViewBuffer) + { + aFrameBuffer->Release (); + aViewBuffer = NULL; + aViewImage = NULL; + } + else + break; +#else + // try to allocate compatible bitmap and necessary resources + initBitmapBuffer (hMemDC, hViewBitmap, + aFrameWidth, aFrameHeight, aViewBuffer); + if (!aViewBuffer) + { + if (hViewBitmap) + DeleteObject (hViewBitmap); + aFrameBuffer->Release (); + hViewBitmap = NULL; + } + else + { + hViewBitmapOld = SelectObject (hMemDC, hViewBitmap); + break; + } +#endif + } + + // not initialized, decrease dimensions + aMaxWidth = aMaxWidth >> 1; + aMaxHeight = aMaxHeight >> 1; + } + + // check if there are proper dimensions + if (aMaxWidth <= 1 || aMaxHeight <= 1) + { + MessageBox (NULL, "Print failed: can't allocate buffer for printing.", + "The operation couldn't be completed.", MB_OK); + + if (aFrameBuffer) + delete aFrameBuffer; +#ifndef HAVE_FREEIMAGE + if (hMemDC) + DeleteDC (hMemDC); +#endif + + return Standard_False; + } + } + + // setup printing context and viewport + GLint aViewPortBack[4]; + GLint aReadBufferPrev = GL_BACK; + GLint anAlignBack = 1; + OpenGl_PrinterContext aPrinterContext (GET_GL_CONTEXT()); + aPrinterContext.SetLayerViewport ((GLsizei)aFrameWidth, + (GLsizei)aFrameHeight); + glGetIntegerv (GL_VIEWPORT, aViewPortBack); + glGetIntegerv (GL_PACK_ALIGNMENT, &anAlignBack); + glPixelStorei (GL_PACK_ALIGNMENT, 4); + + // start document if the printer context is not actually a memory dc + // (memory dc could be used for testing purposes) + if (GetObjectType (hPrnDC) == OBJ_DC) + { + // Initalize printing procedure + di.cbSize = sizeof(DOCINFO); + di.lpszDocName = "Open Cascade Document - print v3d view"; + di.lpszOutput = filename; + + // if can't print the document + if (StartDoc (hPrnDC, &di) <= 0 || StartPage (hPrnDC) <= 0) + { + MessageBox (NULL, "Print failed: printer can't start operation.", + "The operation couldn't be completed.", MB_OK); +#ifndef HAVE_FREEIMAGE + if (hViewBitmap) + { + SelectObject (hMemDC, hViewBitmapOld); + DeleteObject (hViewBitmap); + } + DeleteDC (hMemDC); +#endif + + return Standard_False; + } + } + + // activate the offscreen buffer + aFrameBuffer->BindBuffer (); + + // calculate offset for centered printing + int aDevOffx = (int)(devWidth - width) /2; + int aDevOffy = (int)(devHeight - height)/2; + + // operation complete flag + bool isDone = true; + + if (!IsTiling) + { + aPrinterContext.SetScale ((GLfloat)aFrameWidth /viewWidth, + (GLfloat)aFrameHeight/viewHeight); + aFrameBuffer->SetupViewport (); + redrawView (aview, anunderlayer, anoverlayer, background); + glReadPixels (0, 0, aFrameWidth, aFrameHeight, + GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer); + + // copy result to the printer device and check for errors +#ifdef HAVE_FREEIMAGE + if (!aViewImage->rescale(width, height, FILTER_BICUBIC) || + !imagePasteDC (hPrnDC, aViewImage, aDevOffx, aDevOffy, width, height)) + isDone = imageStretchDC (hPrnDC, aViewImage, aDevOffx, aDevOffy, + width, height); +#else + if (width > aFrameWidth && height > aFrameHeight) + { + SetStretchBltMode (hPrnDC, STRETCH_HALFTONE); + isDone = StretchBlt (hPrnDC, aDevOffx, aDevOffy, width, height, + hMemDC, 0, 0, aFrameWidth, aFrameHeight, SRCCOPY); + } + else + { + isDone = BitBlt (hPrnDC, aDevOffx, aDevOffy, width, height, + hMemDC, 0, 0, SRCCOPY); + } +#endif + } + else + { + // calculate total count of frames and cropping size + Standard_Integer aPxCropx = 0; + Standard_Integer aPxCropy = 0; + Standard_Integer aTotalx = + (Standard_Integer)floor ((float)width /aFrameWidth); + Standard_Integer aTotaly = + (Standard_Integer)floor ((float)height/aFrameHeight); + if (width %aFrameWidth != 0) + { + aPxCropx = (aFrameWidth - width%aFrameWidth)/2; + aTotalx++; + } + if (height%aFrameHeight != 0) + { + aPxCropy = (aFrameHeight - height%aFrameHeight)/2; + aTotaly++; + } + + int anOddPixelx = (width %aFrameWidth) %2; + int anOddPixely = (height%aFrameHeight)%2; + + // calculate scale factor for full frames + Standard_Real aScalex = (Standard_Real)width /aFrameWidth; + Standard_Real aScaley = (Standard_Real)height/aFrameHeight; + + // calculate and set the text scaling factor for printing context + GLfloat aScaleRatex = (GLfloat)aFrameWidth /viewWidth; + GLfloat aScaleRatey = (GLfloat)aFrameHeight/viewHeight; + aPrinterContext.SetScale (aScaleRatex*(GLfloat)aScalex, + aScaleRatey*(GLfloat)aScaley); + + // initialize projection matrix for printer context + TColStd_Array2OfReal aProj (0, 3, 0, 3); + Standard_Real aDef = 0; + aProj.Init (aDef); + aProj(2,2) = 1.0; + aProj(3,3) = 1.0; + + // projection matrix offsets for printer context + // offsets are even numbers + Standard_Real aOffsetx(0), aOffsety(0); + aOffsetx = -(aTotalx-1); + aOffsety = -(aTotaly-1); + + // rect of frame image that will be copied + // and coordinates in view image where to put it + Standard_Integer aLeft = 0, aRight = 0, aBottom = 0, aTop = 0; + Standard_Integer aSubLeft = (Standard_Integer)aDevOffx; + Standard_Integer aSubTop = (Standard_Integer)aDevOffy; + + // draw sequence of full frames + for (int i = 0; i < aTotalx; i++) + { + // offsets are even numbers + aOffsety = -(aTotaly-1); + aSubTop = (Standard_Integer)aDevOffy; + + // calculate cropped frame rect + aLeft = (i == 0) ? aPxCropx : 0; + aRight = (i == aTotalx-1) ? aFrameWidth-(aPxCropx+anOddPixelx) : + aFrameWidth; + + for (int j = 0; j < aTotaly; j++) + { + // no offset for single frames + aProj(3,0) = (aTotalx == 1) ? 0 : -aOffsetx; + aProj(3,1) = (aTotaly == 1) ? 0 : aOffsety; + + // set projection matrix + aProj(0,0) = aScalex; + aProj(1,1) = aScaley; + aPrinterContext.SetProjTransformation (aProj); + + // calculate cropped frame rect + aTop = (j == 0) ? aPxCropy : 0; + aBottom = (j == aTotaly-1) ? aFrameHeight-(aPxCropy+anOddPixely) : + aFrameHeight; + + // draw to the offscreen buffer and capture the result + aFrameBuffer->SetupViewport (); + redrawView (aview, anunderlayer, anoverlayer, background); + glReadPixels (0, 0, aFrameWidth, aFrameHeight, + GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer); +#ifdef HAVE_FREEIMAGE + // cut out pixels that are out of printing area + isDone = imagePasteDC (hPrnDC, aViewImage, aSubLeft, aSubTop, + aRight-aLeft, aBottom-aTop, aLeft, aTop); +#else + isDone = BitBlt (hPrnDC, aSubLeft, aSubTop, aRight-aLeft, aBottom-aTop, + hMemDC, aLeft, aTop, SRCCOPY); +#endif + + // stop operation if errors + if (!isDone) + break; + + // calculate new view offset for y-coordinate + aOffsety += 2.0; + aSubTop += aBottom-aTop; + } + + // stop operation if errors + if (!isDone) + break; + + // calculate new view offset for x-coordinate + aOffsetx += 2.0; + aSubLeft += aRight-aLeft; + } + } + + // complete printing or indicate an error + if (GetObjectType (hPrnDC) == OBJ_DC && isDone == true) + { + EndPage (hPrnDC); + EndDoc (hPrnDC); + } + else if (isDone == false) + { + MessageBox (NULL, "Print failed: insufficient memory or spool error.\nPlease use smaller printer resolution.", + "The opeartion couldn't be completed.", MB_OK); + if (GetObjectType (hPrnDC) == OBJ_DC) + AbortDoc (hPrnDC); + } + + // return OpenGl to the previous state + aPrinterContext.Deactivate (); + glPixelStorei (GL_PACK_ALIGNMENT, anAlignBack); + aFrameBuffer->UnbindBuffer(); + glViewport (aViewPortBack[0], aViewPortBack[1], + aViewPortBack[2], aViewPortBack[3]); + if (aPrevBuffer) + aPrevBuffer->ChangeViewport (aPrevBufferX, aPrevBufferY); + else + delete aFrameBuffer; + + // delete resources +#ifndef HAVE_FREEIMAGE + if (hViewBitmap) + { + SelectObject (hMemDC, hViewBitmapOld); + DeleteObject (hViewBitmap); + } + DeleteDC (hMemDC); +#endif + + return (Standard_Boolean) isDone; + +#else // not WNT + return Standard_False; +#endif } + diff --git a/src/OpenGl/OpenGl_view.cxx b/src/OpenGl/OpenGl_view.cxx index 0360916886..cfd1e3997c 100755 --- a/src/OpenGl/OpenGl_view.cxx +++ b/src/OpenGl/OpenGl_view.cxx @@ -87,6 +87,7 @@ if any was defined #include #include #include +#include /*----------------------------------------------------------------------*/ /* @@ -842,7 +843,22 @@ TelSetViewIndex( Tint Wsid /* Workstation id */, printf("OpenGl_view.c::TelSetViewIndex::glMatrixMode(GL_PROJECTION) \n"); #endif glMatrixMode(GL_PROJECTION); - glLoadMatrixf((GLfloat *) vptr->vrep.mapping_matrix ); + glLoadIdentity(); + +#ifdef WNT + // add printing scale/tiling transformation + OpenGl_PrinterContext* aPrinterContext = + OpenGl_PrinterContext::GetPrinterContext(GET_GL_CONTEXT()); + + if (aPrinterContext) + { + GLfloat aProjMatrix[16]; + aPrinterContext->GetProjTransformation(aProjMatrix); + glLoadMatrixf((GLfloat*) aProjMatrix); + } +#endif + + glMultMatrixf((GLfloat *) vptr->vrep.mapping_matrix ); #ifdef TRACE_MAT printf( "\nTelSetViewIndex WS : %d, view : %d", Wsid, Vid ); diff --git a/src/V3d/V3d_View.cdl b/src/V3d/V3d_View.cdl index d2c821913f..5e4a6089e1 100755 --- a/src/V3d/V3d_View.cdl +++ b/src/V3d/V3d_View.cdl @@ -144,7 +144,8 @@ uses GradientFillMethod from Aspect, FontAspect from OSD, AsciiString from TCollection, - ExtendedString from TCollection + ExtendedString from TCollection, + PrintAlgo from Aspect raises @@ -1606,9 +1607,10 @@ is Print (me; hPrnDC: Handle from Aspect = NULL; showDialog: Boolean = Standard_True; - showBackground: Boolean = Standard_True; - filename: CString = NULL) - is static; + showBackground : Boolean = Standard_True; + filename: CString = NULL; + printAlgorithm : PrintAlgo from Aspect = Aspect_PA_STRETCH) + returns Boolean from Standard is static; ---Level: Public ---Purpose: print the contents of the view to printer with preview. @@ -1625,6 +1627,15 @@ is -- (background is white) -- else set to TRUE for printing with current background color. -- : If != NULL, then the view will be printed to a file. + -- : If you want to select the print algorithm, then you can + -- specify one of existing algorithms: Aspect_PA_STRETCH, Aspect_PA_TILE. + -- Returns Standard_True if the data is passed to the printer, otherwise + -- Standard_False if the print operation failed. This might be related to + -- insufficient memory or some internal errors. All this errors are + -- indicated by the message boxes (on level of OpenGl_GraphicDriver). + -- Warning: This function can reuse FBO assigned to the + -- view on level of OpenGl_GraphicDriver; Please take it into account if + -- you use it for your purposes; -- Warning: Works only under Windows. ToPixMap ( me : mutable; diff --git a/src/V3d/V3d_View_Print.cxx b/src/V3d/V3d_View_Print.cxx index 9bb3164657..6b6975ad5f 100755 --- a/src/V3d/V3d_View_Print.cxx +++ b/src/V3d/V3d_View_Print.cxx @@ -53,18 +53,20 @@ Device::~Device() /* Print Method */ /************************************************************************/ -void V3d_View::Print (const Aspect_Handle hPrnDC, - const Standard_Boolean showDialog, - const Standard_Boolean showBackground, - const Standard_CString filename) const +Standard_Boolean V3d_View::Print (const Aspect_Handle hPrnDC, + const Standard_Boolean showDialog, + const Standard_Boolean showBackground, + const Standard_CString filename, + const Aspect_PrintAlgo printAlgorithm) const { #ifdef WNT if( MyView->IsDefined() ) { if (hPrnDC != NULL) { - MyView->Print(hPrnDC, showBackground, filename) ; - return; + return MyView->Print(hPrnDC, showBackground, + filename, printAlgorithm) ; + } if (device._pd.hDC == NULL || showDialog ) @@ -85,7 +87,7 @@ void V3d_View::Print (const Aspect_Handle hPrnDC, if (!ispd) { - return; + return Standard_False; } if (!(device._pd.hDC)) @@ -101,12 +103,21 @@ void V3d_View::Print (const Aspect_Handle hPrnDC, device._pd.hDevMode = NULL; } MessageBox(0, "Couldn't create Printer Device Context", "Error", MB_OK | MB_ICONSTOP); - return; + return Standard_False; } } - MyView->Print(device._pd.hDC, showBackground, filename) ; + + // process scale factor accordingly to the new printing approach + DEVMODE* aMode = (LPDEVMODE)GlobalLock(device._pd.hDevMode); + + // convert percents to multiplication factor, 100% = 1.0 + Standard_Real aScaleFactor = (Standard_Real) aMode->dmScale / 100.0; + GlobalUnlock (device._pd.hDevMode); + return MyView->Print(device._pd.hDC, showBackground, + filename, printAlgorithm, aScaleFactor) ; } #else Standard_NotImplemented::Raise ("V3d_View::Print is implemented only on Windows"); #endif + return Standard_False; } diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index a5034d7ba9..b3bc92d42e 100755 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -24,6 +24,8 @@ #include #include #include +#include +#include #ifndef WNT #include @@ -1760,6 +1762,141 @@ static int VGraduatedTrihedron(Draw_Interpretor& di, Standard_Integer argc, cons return 0; } +//============================================================================== +//function : VPrintView +//purpose : Test printing algorithm, print the view to image file with given +// width and height. Printing implemented only for WNT. +//============================================================================== +static int VPrintView (Draw_Interpretor& di, Standard_Integer argc, + const char** argv) +{ +#ifndef WNT + di << "Printing implemented only for wnt!\n"; + return 1; +#else + + Handle(AIS_InteractiveContext) aContextAIS = NULL; + Handle(V3d_View) aView = NULL; + aContextAIS = ViewerTest::GetAISContext(); + if (!aContextAIS.IsNull()) + { + const Handle(V3d_Viewer)& Vwr = aContextAIS->CurrentViewer(); + Vwr->InitActiveViews(); + if(Vwr->MoreActiveViews()) + aView = Vwr->ActiveView(); + } + + // check for errors + if (aView.IsNull()) + { + di << "Call vinit before!\n"; + return 1; + } + else if (argc < 4) + { + di << "Use: " << argv[0]; + di << " width height filename [print algo=0]\n"; + di << "width, height of the intermediate buffer for operation\n"; + di << "algo : {0|1}\n"; + di << " 0 - stretch algorithm\n"; + di << " 1 - tile algorithm\n"; + di << "test printing algorithms into an intermediate buffer\n"; + di << "with saving output to an image file\n"; + return 1; + } + + // get the input params + Standard_Integer aWidth = atoi (argv[1]); + Standard_Integer aHeight = atoi (argv[2]); + Standard_Integer aMode = 0; + TCollection_AsciiString aFileName = TCollection_AsciiString (argv[3]); + if (argc==5) + aMode = atoi (argv[4]); + + // check the input parameters + if (aWidth <= 0 || aHeight <= 0) + { + di << "Width and height must be positive values!\n"; + return 1; + } + if (aMode != 0 && aMode != 1) + aMode = 0; + + Image_CRawBufferData aRawBuffer; + HDC anDC = CreateCompatibleDC(0); + + // define compatible bitmap + BITMAPINFO aBitmapData; + memset (&aBitmapData, 0, sizeof (BITMAPINFOHEADER)); + aBitmapData.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + aBitmapData.bmiHeader.biWidth = aWidth ; + aBitmapData.bmiHeader.biHeight = aHeight; + aBitmapData.bmiHeader.biPlanes = 1; + aBitmapData.bmiHeader.biBitCount = 24; + aBitmapData.bmiHeader.biXPelsPerMeter = 0; + aBitmapData.bmiHeader.biYPelsPerMeter = 0; + aBitmapData.bmiHeader.biClrUsed = 0; + aBitmapData.bmiHeader.biClrImportant = 0; + aBitmapData.bmiHeader.biCompression = BI_RGB; + aBitmapData.bmiHeader.biSizeImage = 0; + + // Create Device Independent Bitmap + HBITMAP aMemoryBitmap = CreateDIBSection (anDC, &aBitmapData, DIB_RGB_COLORS, + &aRawBuffer.dataPtr, NULL, 0); + HGDIOBJ anOldBitmap = SelectObject(anDC, aMemoryBitmap); + + Standard_Boolean isSaved = Standard_False, isPrinted = Standard_False; + if (aRawBuffer.dataPtr != 0) + { + if (aMode == 0) + isPrinted = aView->Print(anDC,1,1,0,Aspect_PA_STRETCH); + else + isPrinted = aView->Print(anDC,1,1,0,Aspect_PA_TILE); + + // succesfully printed into an intermediate buffer + if (isPrinted) + { + Handle(Image_PixMap) anImageBitmap = + new Image_PixMap ((Standard_PByte)aRawBuffer.dataPtr, + aWidth, aHeight, + aWidth*3 + aWidth%4, 24, 0); + isSaved = anImageBitmap->Dump(aFileName.ToCString()); + } + else + { + di << "Print operation failed due to printing errors or\n"; + di << "insufficient memory available\n"; + di << "Please, try to use smaller dimensions for this test\n"; + di << "command, as it allocates intermediate buffer for storing\n"; + di << "the result\n"; + } + } + else + { + di << "Can't allocate memory for intermediate buffer\n"; + di << "Please use smaller dimensions\n"; + } + + if (aMemoryBitmap) + { + SelectObject (anDC, anOldBitmap); + DeleteObject (aMemoryBitmap); + DeleteDC(anDC); + } + + if (!isSaved) + { + di << "Save to file operation failed. This operation may fail\n"; + di << "if you don't have enough available memory, then you can\n"; + di << "use smaller dimensions for the output file\n"; + return 1; + } + + return 0; + +#endif +} + //======================================================================= //function : ViewerCommands //purpose : @@ -1826,4 +1963,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) theCommands.Add("vgraduatedtrihedron", "vgraduatedtrihedron : 1/0 (display/erase) [Xname Yname Zname [Font [isMultibyte]]]", __FILE__,VGraduatedTrihedron,group); + theCommands.Add("vprintview" , + "vprintview : width height filename [algo=0] : Test print algorithm: algo = 0 - stretch, algo = 1 - tile", + __FILE__,VPrintView,group); + } diff --git a/src/Visual3d/Visual3d_View.cdl b/src/Visual3d/Visual3d_View.cdl index b2341980f7..91ef918fcd 100755 --- a/src/Visual3d/Visual3d_View.cdl +++ b/src/Visual3d/Visual3d_View.cdl @@ -74,6 +74,7 @@ uses RenderingContext from Aspect, GraphicCallbackProc from Aspect, ColorScale from Aspect, + PrintAlgo from Aspect, CRawBufferData from Image, @@ -1075,12 +1076,14 @@ is -- displayed in . ---Category: Private methods - Print (me; AnUnderLayer : Layer from Visual3d; - AnOverLayer : Layer from Visual3d; - hPrnDC: Handle from Aspect; - showBackground: Boolean; - filename: CString) - is static; + Print (me; AnUnderLayer : Layer from Visual3d; + AnOverLayer : Layer from Visual3d; + hPrnDC : Handle from Aspect; + showBackground : Boolean; + filename : CString; + printAlgorithm : PrintAlgo from Aspect = Aspect_PA_STRETCH; + theScaleFactor : Real from Standard = 1.0) + returns Boolean from Standard is static; ---Level: Internal ---Purpose: print the contents of all layers of the view to the printer. @@ -1089,12 +1092,21 @@ is -- (background is white) -- else set to TRUE for printing with current background color. -- : If != NULL, then the view will be printed to a file. + -- : Select print algorithm: stretch, tile. + -- : Scaling coefficient, used internally to scale the + -- printings accordingly to the scale factor selected in the printer + -- properties dialog. + -- Returns Standard_True if the data is passed to the printer, otherwise + -- Standard_False if the print operation failed due to printer error + -- or insufficient memory. -- Warning: Works only under Windows. - Print (me; hPrnDC: Handle from Aspect; - showBackground: Boolean; - filename: CString) - is static; + Print (me; hPrnDC : Handle from Aspect; + showBackground : Boolean; + filename : CString; + printAlgorithm : PrintAlgo from Aspect = Aspect_PA_STRETCH; + theScaleFactor : Real from Standard = 1.0 ) + returns Boolean from Standard is static; ---Level: Internal ---Purpose: print the contents of the view to printer. @@ -1103,6 +1115,13 @@ is -- (background is white) -- else set to TRUE for printing with current background color. -- : If != NULL, then the view will be printed to a file. + -- : Select print algorithm: stretch, tile. + -- : Scaling coefficient, used internally to scale the + -- printings accordingly to the scale factor selected in the printer + -- properties dialog. + -- Returns Standard_True if the data is passed to the printer, otherwise + -- Standard_False if the print operation failed due to printer error + -- or insufficient memory. -- Warning: Works only under Windows. SetTransparency ( me : mutable; diff --git a/src/Visual3d/Visual3d_View_Print.cxx b/src/Visual3d/Visual3d_View_Print.cxx index 8b775df227..796ea68cf8 100755 --- a/src/Visual3d/Visual3d_View_Print.cxx +++ b/src/Visual3d/Visual3d_View_Print.cxx @@ -14,28 +14,34 @@ /* Print Methods */ /************************************************************************/ -void Visual3d_View::Print (const Aspect_Handle hPrintDC, - const Standard_Boolean showBackground, - const Standard_CString filename) const +Standard_Boolean Visual3d_View::Print + (const Aspect_Handle hPrintDC, + const Standard_Boolean showBackground, + const Standard_CString filename, + const Aspect_PrintAlgo printAlgorithm, + const Standard_Real theScaleFactor) const { - Print (MyViewManager->UnderLayer (), - MyViewManager->OverLayer (), - hPrintDC, - showBackground, - filename); + return Print (MyViewManager->UnderLayer (), + MyViewManager->OverLayer (), + hPrintDC, showBackground, + filename, printAlgorithm, + theScaleFactor); } -void Visual3d_View::Print (const Handle(Visual3d_Layer)& AnUnderLayer, - const Handle(Visual3d_Layer)& AnOverLayer, - const Aspect_Handle hPrintDC, - const Standard_Boolean showBackground, - const Standard_CString aFilename) const +Standard_Boolean Visual3d_View::Print + (const Handle(Visual3d_Layer)& AnUnderLayer, + const Handle(Visual3d_Layer)& AnOverLayer, + const Aspect_Handle hPrintDC, + const Standard_Boolean showBackground, + const Standard_CString aFilename, + const Aspect_PrintAlgo printAlgorithm, + const Standard_Real theScaleFactor) const { - if (IsDeleted ()) return; + if (IsDeleted ()) return Standard_False; - if ((! IsDefined ()) || (! IsActive ())) return; + if ((! IsDefined ()) || (! IsActive ())) return Standard_False; - if (! MyWindow->IsMapped ()) return; + if (! MyWindow->IsMapped ()) return Standard_False; Aspect_CLayer2d OverCLayer; Aspect_CLayer2d UnderCLayer; @@ -44,6 +50,7 @@ void Visual3d_View::Print (const Handle(Visual3d_Layer)& AnUnderLayer, if (! AnOverLayer.IsNull ()) OverCLayer = AnOverLayer->CLayer (); if (! AnUnderLayer.IsNull ()) UnderCLayer = AnUnderLayer->CLayer (); - MyGraphicDriver->Print (MyCView, UnderCLayer, OverCLayer, - hPrintDC, showBackground, aFilename); + return MyGraphicDriver->Print (MyCView, UnderCLayer, OverCLayer, + hPrintDC, showBackground, aFilename, + printAlgorithm, theScaleFactor); }