====================
Off-Screen Rendering
====================

Visualize supports rendering the scene to an offscreen window. This is accomplished using an offscreen image buffer, and ``HPS::OffScreenWindowKey`` serves as a high-level handle to the buffer. It allows you to inspect or manipulate the image data without the user seeing it rendered on the screen.

After you have the key, simply include a root segment as you would with any normal window. Once a segment is included by a window key, its entire hierarchy will enter the rendering pipeline for that window.

If you want to choose a specific driver interface to use with the window you create, you must use an ``HPS::OffScreenWindowOptionsKit`` to specify it. If you do not specify a driver interface, Visualize will default to the ``HPS::Window::Driver::Default3D`` interface. Whatever hardware is used to draw into a conventional on-screen window is also used to draw into a memory buffer, so the scene should be identical in both contexts (Visualize will not use a software mode to do any offscreen rendering).

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_offscreen_window.cpp
		   :start-after: //! [offscreen_window]
		   :end-before: //! [offscreen_window]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_offscreen_window.cs
		   :start-after: //! [offscreen_window]
		   :end-before: //! [offscreen_window]
		   
The segment hierarchy in an offscreen window behaves the same way as a hierarchy in a normal window. So, you'll have to set all your cameras, lighting, and other attributes in the same way. If you need to render an existing scene into an offscreen window, it is recommended that you include the existing scene's root segment into the offscreen window using an include segment rather than trying to duplicate the scene by rebuilding it. Using an include segment saves memory, time, and all changes to the existing scene are automatically reflected in the other window.


.. _transparent_background:

Rendering to an offscreen window with a transparent background
---------------------------------------------------------------

It may be desirable to render images with a transparent background. This is only supported when the render target is an offscreen window.

To make the window background transparent, set the opacity level in the window options kit <i>before</i> creating the window:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_offscreen_window.cpp
		   :start-after: //! [opacity]
		   :end-before: //! [opacity]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_offscreen_window.cs
		   :start-after: //! [opacity]
		   :end-before: //! [opacity]
		   
**Limitations:** Rendering to a transparent background is only supported in the 3D shader drivers. Additionally, bloom is not supported.


.. _offscreen_image_buffer:

Accessing the Off-Screen Image Buffer
=====================================

Before accessing the image data, you have to make sure the rendering is complete. Normally, you would call ``HPS::WindowKey::Update`` to render a scene. However, due to the multithreaded nature of Visualize, the rendering may not be finished by the time you try to use the image. Therefore, it is appropriate to wait for the image to complete using an ``HPS::UpdateNotifier``:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_offscreen_window.cpp
		   :start-after: //! [notifier_offscreen]
		   :end-before: //! [notifier_offscreen]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_offscreen_window.cs
		   :start-after: //! [notifier_offscreen]
		   :end-before: //! [notifier_offscreen]
		   
The raw image data is accessed through an ``HPS::ImageKit``. Once you have the kit, you can manipulate the data in many ways. For example, you can write the image to a file, use it as a texture, or merely inspect it by iterating over its array. This code sample demonstrates how to write the image to a PNG:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_offscreen_window.cpp
		   :start-after: //! [get_image_data]
		   :end-before: //! [get_image_data]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_offscreen_window.cs
		   :start-after: //! [get_image_data]
		   :end-before: //! [get_image_data]
		   
Alternatively, you may want to modify part of the image data before doing something else with it. In that case, you can get the raw image as 24-bit RGB data using an ``HPS::ImageKit`` with an ``HPS::OffScreenWindowOptionsControl``:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_modify_offscreen_image_data.cpp
		   :start-after: //! [modify_offscreen_image_data]
		   :end-before: //! [modify_offscreen_image_data]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_modify_offscreen_image_data.cs
		   :start-after: //! [modify_offscreen_image_data]
		   :end-before: //! [modify_offscreen_image_data]
		   
		   
Making Screenshots
------------------

It is easy to make a screenshot by rendering your scene into an ``HPS::OffscreenWindowKey`` and then showing the rendered image into an ``HPS::ImageKit`` as described above. However, if you don't need to inspect or alter the image data, there are more convenient and less memory-intensive ways of doing this. See our sections on :ref:`rendered screenshots <prog_guide/0404_images:Saving a screenshot as an image>` and :ref:`file import screenshots <prog_guide/0901_importing_files:Saving screenshots>` for instructions on using alternate methods.


.. _render_to_texture:

Rendering to a Texture
======================

It is possible to associate an offscreen window directly with an :doc:`image definition <0402_definitions>`. When doing so, rendering to the offscreen window will automatically update the image definition with new data. The image definiton can then be used as a texture, a window background, or exported for other uses. If you want to render to a texture, you must make the association between the offscreen window and the target image definition at the time you create the window.

**NOTE:** While there are other ways of rendering to a texture, the method described here is recommended because it writes to GPU memory. Other methods that do not use the ``HPS::ImageDefinition`` target will render the image to main memory before transferring it to GPU memory. This incurs a performance penalty when continuously updating the render target.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_offscreen_window.cpp
		   :start-after: //! [img_def_target]
		   :end-before: //! [img_def_target]
		   
	.. group-tab:: C#

		OffscreenWindowKey owc = Database.CreateOffScreenWindow(myImageDefinition);

		// be sure to wait for the image to render before using it!
		UpdateNotifier updateNotifier = owc.UpdateWithNotifier();
		updateNotifier.Wait();

Assuming you have the image definition already created, the last step is to apply it to a piece of geometry as a texture. High-level steps are shown below:

.. tabs::

	.. group-tab:: C++
	
		HPS::TextureOptionsKit textureOptionsKit;
		 
		// see the table below about parameterization sources
		textureOptionsKit.SetParameterizationSource(HPS::Material::Texture::Parameterization::UV);      
		 
		// makes the image into a texture
		portfolioKey.DefineTexture("my_texture", imageDefinition, textureOptionsKit); 

		// ... [set vertex parameters]

		mySegmentKey.GetMaterialMappingControl().SetFaceTexture("my_texture");

		myWindowKey.Update();
		   
	.. group-tab:: C#

		HPS.TextureOptionsKit textureOptionsKit = new HPS.TextureOptionsKit();
		 
		// see the table below about parameterization sources
		textureOptionsKit.SetParameterizationSource(HPS.Material.Texture.Parameterization.UV);      
		 
		// makes the image into a texture
		portfolioKey.DefineTexture("my_texture", myImageDefinition, textureOptionsKit); 

		// ... [set vertex parameters]

		mySegmentKey.GetMaterialMappingControl().SetFaceTexture("my_texture");

		myWindowKey.Update();
		   

Complete instructions on creating an image definition and applying it as a texture can be found :doc:`here <0503_textures>`.


Hardcopy
========

HOOPS Visualize offers the ability to print (see :ref:`limitations <limitations>`) as well as export to PostScript and 2D PDF. Collectively, these are referred to as "hardcopy". ``HPS::Hardcopy`` is an extensible class for writing hardcopy versions of your model. The ``HPS::Hardcopy`` class has one purpose - to reproduce your scene as accurately as possible in the output medium.

Hardcopy works by rendering the faces in your model to an image in one pass, then doing a hidden line rendering over that image in the second pass. Text, lines, edges, curves, and other vector data are drawn in the second pass. This results in output which can be efficiently handled by a printer.

The background image, generated in the first pass, can be extremely large. For example, an 8.5" x 11" image at 600 dpi results in 128 MB of data. Visualize can't render an image that large, so ``HPS::Hardcopy`` divides that image up into smaller parts which it can handle. The smaller parts are compressed, written to temporary files, then reassembled and cropped before being sent to the output file. This enables ``HPS::Hardcopy`` to make arbitrarily large output files.

When printing, you must provide the window key from your scene hierarchy to ``HPS::Hardcopy``. Additionally, there is an ``HPS::Hardcopy::File::ExportOptionsKit`` through which you can set size and resolution. For example:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_hardcopy.cpp
		   :start-after: //! [hardcopy]
		   :end-before: //! [hardcopy]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_hardcopy.cs
		   :start-after: //! [hardcopy]
		   :end-before: //! [hardcopy]

By default, HOOPS Visualize will print your scene with a white background. However, this can be controlled by using the ``HPS::Hardcopy::File::ExportOptionsKit::SetBackgroundPreference()`` function.


Printing to Scale
-----------------

In addition to the printing method described above, HOOPS Visualize also offers the ability to print to scale. HOOPS Visualize operates in a unitless measurement system. For example, if you insert a line of length 2, its length is not expressed in inches, centimeters or any other unit. '2' is simply a length which is relative to the size of other geometry in the scene - it does not correspond to any real unit of measurement.

Printing to scale allows you to assign a real-world unit value to Visualize's internal unitless measurements for the purpose of printing or exporting to PDF and Postscript. To enable print-to-scale, simply set a positive value for the scale::

	HPS::Hardcopy::File::ExportOptionsKit exportOptionsKit;
	exportOptionsKit.SetScale(2);  // enables print-to-scale with a scale factor of 2
	exportOptionsKit.UnsetScale(); // disables print-to-scale

As an example, if you wanted to export a model to PDF, you would first set the scale, and specify the output context in the export function::

	HPS::Hardcopy::File::ExportOptionsKit exportOptionsKit;
	exportOptionsKit.SetScale(2);
	HPS::Hardcopy::File::Export("foo", Driver::PDF, window, exportOptionsKit); // this print is to scale

In the hardcopy output, each HOOPS Visualize internal unit would correspond to two real-world inches. Therefore, if line of length 2 was inserted in a Visualize scene, it will have a real-world length of 4 inches when printed or exported to PDF.

A side effect of printing to scale is that the printed output will not necessarily match what is visible on screen. The output will be scaled up or down and given a new aspect ratio so that it will fill the printable area of the specified output device (i.e. a printer or the size of the output file as specified in the export options kit), with the scene centered around the camera target.

Please note that the print to scale feature is not defined for a perspective camera. If the user tries to print to scale with a perspective camera, the camera projection will be temporarily changed to orthographic while the print takes place. When setting a scale, the scale value needs to be a positive number.
If the user tries to set a zero or negative number, a warning will be generated and the request will be ignored. Print to scale is disabled by default.


.. _limitations:

Hardcopy limitations

Printing directly to paper only works in Windows C++ applications, and is not currently supported for C# applications. This is because printing to paper uses the Windows GDI. One of the main differences is you must use the options kit ``HPS::Hardcopy::GDI::ExportOptionsKit`` instead of a ``HPS::Hardcopy::File::ExportOptionsKit``.

.. tabs::

	.. group-tab:: C++
	
		.. code-block:: cpp
	
			void Cmfc_simpleView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
			{
				Hardcopy::GDI::ExportOptionsKit options;
				Hardcopy::GDI::Export(
					(long)pDC->m_hDC,
					(long)pDC->m_hAttribDC,
					_canvas.GetWindowKey(),
					options);
			}

On Linux and OS X, printing is a two-step process. First, export your scene to a 2D PDF or Postscript file. Next, you must make your own calls to CUPS (or the printing API of your choice) in order to send the data to the printer.
