===================
Supported Platforms
===================

.. list-table::
    :header-rows: 1
    
    * - Platform
      - Architecture
      - Minimum supported OS
      - Compiler
    * - Windows
      - x64
      - Windows 10
      - VS 2019, VS 2022
    * - Linux
      - ARM64, x86 or x64
      - Debian buster
      - gcc 10.4 / glibc 2.28
    * - macOS
      - ARM64 or x64
      - macOS 10.9
      - Xcode 12.2 (LLVM)
    * - iOS
      - ARM64, x86_64
      - iOS 11.0
      - Xcode 12.2 (LLVM)
    * - Android
      - arm64-v8a, x86_64
      - Android 5.1
      - Android NDK r27c
        

Windows
=======

The officially supported platform and development environment for Windows is noted in the table above. You can choose to develop in either C++ or C#. The solution file is called *visualize_vc<version>.sln*; it contains all the projects you might need to compile during the course of your development cycle, including the MFC Sandbox, a WPF Sandbox, and the :doc:`sample code </guides/sample_code>`. The default installation directory is of the form *hoops_visualize_hps<version>_vc<version>*.

Tech Soft provides |HPSNOW| libraries as pre-compiled binaries, thus, there is nothing extra that needs to be built. Your application links to the |HPSNOW| libraries during the build process and subsequently to the DLLs at runtime.

C++
---

A few modifications must be made to a clean project file in order to compile a |HPSNOW| application:

#. The first step is to set the include file path in the project. It should be set to the *include* subdirectory of the root install location.

#. Add the desired |HPSNOW| libraries to the project

#. Ensure the dynamic libraries are in the environment PATH or your application's working directory. The DLLs are found in *<install_dir>\\bin\\<platform_name>*, and the names correspond with the library names from step 2. For example, if you are using functionality found in *hps_sprk.lib*, the DLL is named *hps_sprk.dll*.

When running your |HPSNOW| application, the operating system will need to locate the |HPSNOW| DLLs in the environment ``PATH`` or the application's directory.


Conflicting Macros in Windows C++ Builds
----------------------------------------

There is a macro conflict that occurs frequently with certain Windows headers. The problem is that these headers ``#define`` a number of common names. Since ``#define`` can't be scoped by a namespace or class, they cause conflicts with other code. The most commonly encountered conflicts are ``min``, ``max``, and ``Window``.

The solution is to simply include the |HPSNOW| header file after any Windows headers. This will enable |HPSNOW| to determine if ``_WINDOWS_`` is defined, and if so, it will undefine the conflicting macros.


C#
--

Similar to C++, your C# application must reference the |HPSNOW| C# assemblies that it requires. They are located in  in *<HPS_INSTALL_DIR>\bin\<platform_name>*. The assembly names correspond to the C++ DLLs noted in the previous subsection, with one minor difference. The names include *cs* - for example, *hps_core.dll* becomes *hps_cs_core.dll*

The C# assemblies depend on the corresponding C++ DLLs. Thus, when using the *hps_cs_core.dll* assembly, the supporting C++ binary called *hps_core.dll* must also be in the environment PATH or the application's directory. The C++ DLLs are also located in *<HPS_INSTALL_DIR>\bin\<platform_name>*.

Additionally, when compiling, the platform target must be either 32 or 64-bit. The "Any CPU" target will not work.


Linux
=====

The officially supported platform and development environment for Linux is noted in the table at the top of this page. There is a makefile for the sample applications (*hps_samples*), and a subdirectory for the QT sandbox (*qt_sandbox*).

For the samples, users can navigate to samples/code/cpp and run

``make <platform>``

...where <platform> is one of [linux32, linux32-debug, linux64, linux64-debug].

For the QT sandbox, there is a *qt_sandbox.pro* file which can be used to build the application using QtCreator. If you are using |HPSNOW| on a Linux platform and directly or indirectly invoking the X11 API outside of |HPSNOW|, please see the :ref:`general/supported_platforms:Special Platform Initialization` section.


OSX
===

The officially supported platform and development environment for OSX is noted in the table at the top of this page. There is a workspace for the sample applications (*hps_samples_osx*), and subdirectories for the Cocoa sandbox (*cocoa_sandbox*) and QT sandbox (*qt_sandbox*).

Please be aware of special requirements when creating and managing windows. Specifically, window creation must occur on the main thread. Additionally, after the window is resized, the application must make an update on the main thread. Typically this will happen in the ``NSView::drawRect`` method.

If you do not manage your windows this way, it could lead to undefined behavior!


Mobile Support
==============

The |HPSNOW| Mobile development framework allows you to code once for both systems to maintain platform-independent |HPSNOW| code. 

This applies especially to events and event handling, where the interface related to user input is abstracted from platform-specific GUI or language. The sandboxes are set up so that the platform-specific events will trigger |HPSNOW| function calls:

.. image:: images/gui_logic.png

If you choose not to use the framework provided by the sandboxes, you will have to coordinate this event handoff yourself.


iOS
===

The officially supported platform and development environment for iOS is noted in the table at the top of this page. There is no top-level workspace. The iOS package provides three library files, *libhps_core.a*, *libhps_sprk.a*, and *libhps_sprk_ops.a*. 

In addition to the |HPSNOW| libraries mentioned above, your application should also link to these third-party libraries:

* *quartzcore.framework*
* *opengles.framework*
* *libz.1.2.5.dylib*

**NOTE:** You must be registered in the iOS developer program. This step is required in order to run on a physical iOS device (as opposed to just running on the simulator). 


The iOS Sandbox
---------------

The iOS Sandbox is a sample application which shows how to integrate |HPSNOW| into an iOS app. It can be found at *<HPS_INSTALL_DIR>/samples/ios_sandbox/iOS-Sandbox.xcodeproj*. iOS developers are encouraged to review it or use it as a template when writing their own |HPSNOW| application.

Of particular interest is the ``MobileSurfaceView`` class, which provides the infrastructure. ``MobileSurfaceView`` is a subclass of the Cocoa ``UIView`` class. Here, we are specifying that we want a ``CAEGLLayer`` as the view's layer type. Your application will need to do something similar::

	+ (Class)layerClass
	{
		// Indicate that we will be using OpenGL ES
		return [CAEAGLLayer class];
	}

Additionally, the ``MobileSurfaceView`` init function includes the following initialization. If you create a custom view class you will need to do this as well::

	CAEAGLLayer * eaglLayer = static_cast<CAEAGLLayer*>(self.layer);
	eaglLayer.opaque = TRUE;
	eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
								[NSNumber numberWithBool:FALSE],
								kEAGLDrawablePropertyRetainedBacking,
								kEAGLColorFormatRGBA8,
								kEAGLDrawablePropertyColorFormat, nil];

Any model that is to be loaded by the iOS Sandbox must be added to the Xcode project.


Handling Input Events
---------------------

The iOS Sandbox will listen for events generated by the operating system, use them to build |HPSNOW| events, then inject the event objects into the |HPSNOW| event queue. If you do not use the iOS Sandbox as a template, you will have to make these connections yourself in order for |HPSNOW| to receive user input. You can see how input events are passed to |HPSNOW| by inspecting the sandbox code. For example, the sandbox injects a touch-down event in this way::

	// MobileSurfaceView.mm (iOS-specific code)

	- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
		int xPosArray[MAX_TOUCHES];
		int yPosArray[MAX_TOUCHES];
		int idArray[MAX_TOUCHES];

		int numTouches = [self buildTouchEvent:touches
							   withXArray:xPosArray
							   withYArray:yPosArray
							   withIdArray:idArray];

		self.surfacePointer->touchMove(numTouches, xPosArray, yPosArray, idArray);
	}

``self.surfacePointer->touchMove`` refers to the following platform-independent function::

	// MobileSurface.cpp (platform-independent code)

	void MobileSurface::touchMove(int numTouches, int xposArray[], int yposArray[], int idArray[])
	{
		InjectTouchEvent(HPS::TouchEvent::Action::Move, numTouches, xposArray, yposArray, idArray);
	}

As mentioned above, you are encouraged to use the iOS Sandbox as a template for your own application, as it will maintain platform independence related to events and event handling. All the platform-independent code related to the iOS Sandbox can found in *<HPS_INSTALL_DIR>/samples/mobile_shared*.


Android
=======

The officially supported platform and development environment for Android is noted in the table at the top of this page.

.. only:: not spatial
	
	The Android package provides four binary libraries, *libhps_core.so*, *libhps_sprk.so*, *libhps_sprk_ops.so*, and *libhps_sprk_exchange.so*.
	
.. only:: spatial

	The Android package provides three binary libraries, *libhps_core.so*, *libhps_sprk.so*, and *libhps_sprk_ops.so*.

The libraries mentioned above are C++ native binaries. While the |HPSNOW| sandbox applications for Android conduct all GUI instantiation and interaction in Java via the Android SDK, the interaction with the |HPSNOW| interface is implemented in C++ with CMake as the make language. An example of how to combine the C++ and Java code into an application can be found in the Android Sandbox project.

To build for Android, you must also have Python in your environment's path.


The Android Sandbox
-------------------

The Android Sandbox is a sample application which shows how to integrate |HPSNOW| into an Android app. It can be found at *<HPS_INSTALL_DIR>/samples/android_sandbox*. Developers are encouraged to review it or use it as a template when writing their own |HPSNOW| application. If you do not start with the Sandbox, you will have to create much of the "glue" code yourself (see "Android Sandbox-Specific notes" below).


Android Sandbox Requirements
----------------------------

In addition to the requirements listed in the table at the top of this page, the sandbox project also requires:

* Android Studio 2.2+
* Python 2.7+
* Java Runtime Environment
* You may need to manually install the appropriate USB driver for your Android device. See `<http://developer.android.com/tools/extras/oem-usb.html>`_ for more info.

The configuration options for the *android_sandbox* should be set via the *local.properties* file contained in the root folder of the sandbox (the *local.properties* file will be generated when you open the project in Android Studio). The *android_sandbox* acknowledges the following variables:

.. only:: not spatial

	.. list-table::
			:header-rows: 0
			
			* - **ndk.abis**
			  - This should contain a comma separated list of native architectures you wish to target. This defaults to all architectures (x86_64, arm64-v8a).
			* - **ndk.arguments**
			  - This passes additional arguments to the NDK build process. For example, you could pass "-DUSING_EXCHANGE=1" here to enable HOOPS Exchange support.
			* - **ndk.dir**
			  - This should point to the root directory of the Android NDK you are using.
			* - **sdk.dir**
			  - This should point to the root directory of the Android SDK you are using.
		  
.. only:: spatial

	.. list-table::
			:header-rows: 0
			
			* - **ndk.abis**
			  - This should contain a comma separated list of native architectures you wish to target. This defaults to all architectures (x86_64, arm64-v8a).
			* - **ndk.arguments**
			  - This passes additional arguments to the ndk build process. 
			* - **ndk.dir**
			  - This should point to the root directory of the Android NDK you are using.
			* - **sdk.dir**
			  - This should point to the root directory of the Android SDK you are using.



.. only:: not spatial

	For example, you could populate your *local.properties* file to look like the following:
	
	.. code-block:: none

		# escape ':' and '=' since they are special characters
		sdk.dir=T\:\Android\android-sdk-windows
		ndk.dir=C\:\android-ndk-r27c
		
		# these are comma separated lists with NO spaces in between
		ndk.abis=x86_64,arm64-v8a # only compile for 64 bit archs
		ndk.arguments=-DUSING_EXCHANGE=1 # enable exchange support

.. only:: spatial

	For example, you could populate your *local.properties* file to look like the following:
	
	.. code-block:: none

		# escape ':' and '=' since they are special characters
		sdk.dir=T\:\Android\android-sdk-windows
		ndk.dir=C\:\android-ndk-r27c
		
		# these are comma separated lists with NO spaces in between
		ndk.abis=x86_64,arm64-v8a # only compile for 64 bit archs


Android Sandbox-specific Notes
------------------------------

Any model that is to be loaded by the Android Sandbox must be present in the *hps/samples/android_sandbox/app/src/main/assets/datasets*.

Since |HPSNOW| is written in C++ and Android uses Java, the JVM must use JNI to call |HPSNOW| methods from Java. For event handling, |HPSNOW| handles this process for you during the build using a Python script. The script examines your C++ event handler declarations, creates corresponding Java functions, and sets up the JNI calls. The benefit of this system is that you can do all of your programming in C++ and you don't have to worry about JNI. Additionally, platform-independence is maintained.

As mentioned above, you are encouraged to use the Android Sandbox as a template for your own application, as it will maintain platform independence related to events and event handling. All the platform-independent code related to the Android Sandbox can found in *<HPS_INSTALL_DIR>/samples/mobile_shared*.

You may notice that after opening the sandbox project in Android Studio, the project structure looks familiar. The *jni* folder contains the Java-C++ interface. The *samples/mobile_shared* directory contains files common to all mobile platforms. Of particular interest is *UserMobileSurface.h*. In that file, you'll see the GUI event handler function declarations are all preceded by the ``SURFACE_ACTION`` identifier. During the build process, the Python script *sip.py* (requires Python 2.7+) uses these tags to automatically generate the Java-C++ interface wrappers. In *UserMobileSurface.cpp*, you'll see the implementation function of each ``SURFACE_ACTION``. Any new GUI component you add to your application should follow this paradigm when calling |HPSNOW|.

.. image:: images/android_actions.png

You should not modify any of the files that are auto-generated. Auto-generated files all have a comment near the top that looks like this::

	// Auto-generated file

Any parameters present in your C++ event function declarations will be marshalled by *sip.py* into a form that is usable by C++:

* ``char const *`` becomes ``String``
* ``char *`` becomes ``StringBuffer``
* ``int []`` becomes arrays and ``out`` parameters

Instructions on using |HPSNOW| operators for handling user input events can be found in the Programming Guide, :doc:`section 6 </prog_guide/0601_standard_operators>`.


Android-specific Issues
-----------------------

There is a known issue with Gradle 3.5.3+ and NDK versions r18b or older where it doesn't recognize the usage of the "c++_shared" or "c++_static" toolchains. To avoid this error, don't accept dialog prompts asking you to upgrade the sandbox Gradle version.


.. only:: not spatial

	Using the Android Sandbox with Exchange
	---------------------------------------
	
	While the |HPSNOW| Android package includes *libhps_sprk_exchange.so*, the Android Sandbox does not link against it or package it by default. To enable this, we must first inform the Android Sandbox of where your HOOPS Exchange installation is. This can be done by setting the ``HEXCHANGE_INSTALL_DIR`` environment variable on your machine, which points to your local HOOPS Exchange installation.

	Next, we need to inform the C++ code / makefiles that HOOPS Exchange is being used - this can be done by editing the *ndk.args* variable of the *local.properties* file as shown under the Android Studio Requirements section::

		USING EXCHANGE := 1

	Lastly, we need to tell the Java code to load the Exchange shared objects, which can be done by navigating to *hps/samples/android_sandbox/app/src/main/java/com/techsoft3d/hps/sandbox/ViewerUtils.java* and setting the ``USING_EXCHANGE`` variable to true.

	Limitations
	-----------
	
	Any ``SURFACE_ACTION`` function declaration must be written on a single line. *sip.py* cannot process multiline function declarations.


Using |HPSNOW| on a Virtual Machine
===================================

The above operating systems are thoroughly tested and officially supported when installed on bare metal, and Developer Support will attempt to reproduce and troubleshoot |HPSNOW| problems that you may encounter when using a bare metal configuration. We recognize that developers and end-users may wish to utilize an operating system as a virtual machine (VM), but as there are several dozen VM products, we cannot provide official testing and support for VMs. |HPSNOW| can function on a VM, but the behavior depends on how the following conditions are met:

#. The VM operating system must meet the |HPSNOW| system requirements, which includes `fully compliant OpenGL or Direct3D runtime support <https://developer.techsoft3d.com/hoops/visualize/graphics-cards>`_. To verify that a VM operating system is set up to run one (or both) of those interfaces, you should utilize one of the 3D configuration tools included with the operating system. The glxinfo utility validates that OpenGL is set up on Linux systems, and the *DxDiag.exe* utility validates that DirectX is set up on Windows. In order to validate the OpenGL set up on Windows, you could utilize a 3rd party or open source utility such as GLMark.

#. The VM vendor must provide a compliant and stable VM implementation of the operating system and 3D APIs. Note that 3D performance, stability, and functionality may vary greatly depending on the VM product being used. For example, additional VM modules may be required for 3D support, the VM vendor may support a limited range of GPUs, OpenGL/Direct3D support may be emulated in software, etc...

Please consult your VM documentation or vendor for details about how to meet the |HPSNOW| system requirements and address any VM performance or functionality limitations. Tech Soft 3D does not provide technical support for VM-specific problems which are not reproducible on a bare metal installation.


Special Platform Initialization
===============================

If you are using |HPSNOW| on a Linux / Unix platform and directly or indirectly invoking the X11 API outside of |HPSNOW|, you will need to make a call to 
`XInitThreads <https://www.x.org/archive/X11R6.8.2/doc/XInitThreads.3.html>`_ as the first X11 function in your application.
