# dpLib #

__dpLib__ is a software library for applying image correction based on the correction data generated by domeprojection.com ProjectionTools. __dpLib__ supports __DirectX 9__, __DirectX 11__, __DirectX 12__, __OpenGL__ and __Vulkan__.

## Dependencies ##

* [CodeMeter runtime](www.codemeter.de/de/service/downloads.html)

## Usage ##

To create and initialize the library a *dpContext* have to be created, which is necessary for any further function call. To create a *dpContext* call *dpCreateContext* somewhere in initialization part. After the context is created successful the correction settings have to be loaded from a configuartion file. This is done with a call to *dpLoadConfigurationFromFile*. After these both functions are called successful the *dpContext* is configured and ready to use.
Right before the engine starts rendering the scene call *dpSetActiveChannel* with the desired channel id to prepare the *dpContext*. Then call *dpPreDraw* to retrieve the correct projection matrix or frustum for further rendering. After the engine has rendered the whole scene a call to *dpPostDraw* applies the correction to the scene.
The following pseudo code snippet shows the general usage of __dpLib__.

```cpp
dpContext* g_pContext;
dpCreateContext(&g_pContext,...)
dpLoadConfigurationFromFile(g_pContext,...)

while(running)
{
    for each channel
    {
        dpSetActiveChannel(g_pContext,...)
        dpPreDraw(g_pContext,...)

        .. render the scene ..

        dpPostDraw(g_pContext,...)

        .. buffer swap ..
    }
}

dpDestroyContext(g_pContext)
```

### Coordinate System ###

__dpLib__ internally works with a right handed coordinate system which means **X** goes from left to right, **Y** from bottom to top and **Z** from front to back.

![coordinate system](coordinatesystem.png "dpLib coordinate system")

Heading/Yaw is the clockwise rotation around the Y-axis, pitch is the counter clockwise rotation around the X-axis and bank/roll is the counter clockwise rotation around the Z-axis.

The order of rotation is heading/yaw first, then pitch, then bank/roll. Assuming matY defines the rotation around the y-axis, matP defines the rotation around the x-axis and matR defines the rotation around the z-axis. The resulting rotation matrix gets calculated by matY * matP * matR.

### Configuration File ###

The following section describes the configuration file used by __dpLib__ in order to configure the correction data to use for each channel.

```xml
<?xml version="1.0" encoding="utf-8"?>
<dpCorrection>
    <!-- type of correction //-->
    <type>0</type>
    <!-- gamma used in ProjectionTools Mapper //-->
    <gamma>2.2</gamma>
    <!-- gamma for source and output //-->
    <input-gamma>2.2</input-gamma>
    <output-gamma>2.2</output-gamma>

    <!-- correction data per channel //-->
    <channel id="0" .../>
    <channel id="1" .../>
</dpCorrection>
```

The number of attributes for a channel tag depends on the selected correction type. __type__ and __gamma__ are set for all channels. To configure static correction the attributes *warpmap* and *frustum* are needed, for dynamic correction *shape* and *target* have to be configured. The attributes *blending*, *blacklevel* and *secondary-blending* are used in both cases.

* static correction
  * warpmap, blending, secondary-blending, blacklevel and frustum
* dynamic correction
  * blending, secondary-blending, blacklevel, shape and target

| tag | description |
| --- | ----------- |
| //__type__ | 0: static correction , 1:dynamic correction |
| //__gamma__ | the gamma value specified in ProjectionTools Mapper |
| //__input-gamma__ | the gamma value of the source image |
| //__output-gamma__ | the desired output gamma value |
| //__channel__[@*id*] | the channel number this tag describes |
| //__channel__[@*warpmap*] | warpmap specifying the correction to apply (for OpenGL only) (for static correction only) |
| //__channel__[@*frustum*] | virtual camera configuration (for static correction only) |
| //__channel__[@*blending*] | blending to apply (for OpenGL only) |
| //__channel__[@*secondary-blending*] | secondary blending to apply (for all graphics engines) |
| //__channel__[@*blacklevel*] | blacklevel to apply (for OpenGL only) |
| //__channel__[@*shape*] | mesh defining the screen shape (for dynamic correction only) |
| //__channel__[@*target*] | mesh defining the target rectangle (for dynamic correction only) |
| //__channel__[@*input-gamma*] | the input gamma value |
| //__channel__[@*output-gamma*] | the output gamma value |
| //__channel__[@*directional-shading*] | color correction texture to apply eyepoint dependent white-point correction (for dynamic correction only) |

All relative file paths are interpreted as relative to configuration file path. When 'c:/file/to/config.xml' is the path the configuration file is located, all relative paths are interpreted as relative to 'c:/file/to'. A relative path 'data/frustum_1.csv' is resolved to 'c:/file/to/data/frustum_1.csv'.

Here are a set of example configurations.

* [3 channel static correction](config_3ch_sta.xml "static correction")
* [3 channel dynamic correction](config_3ch_dyn.xml "dynamic correction")

### Generating Correction Data ###

Use the __domeprojectionSDK Exporter__ from within __Mapper3D__ or __MapperPM__ to generate valid correction datasets for the dpLib. This will include a configuration file paired with multiple data files for warping, blending etc..


## API Documentation ##

__dpLib__ provides for each graphics engine the same set of functions. According to the graphics engines specifics different parameters are nessecary.

An engine specific suffix is appended to the function names, which is abbreviated in the following documentation as [API]:

Engine Name | Suffix
----------- | -------
DirectX 9   | D3D9
DirectX 11  | D3D11
DirectX 12  | D3D12
OpenGL      | OpenGL
Vulkan      | Vulkan

In general __dpLib__ provides the following set of functions. Each function returns a *dpResult* indicating success or failure. In case of failure, __dpGetErrorString__ returns a more detailed error description.

### Rendering ###

* dpResult __dpCreateContext[API]__( *dpContext*** ppContext, ...);
* dpResult __dpDestroyContext[API]__( *dpContext** pContext, ...);
* dpResult __dpLoadConfigurationFromFile[API]__( *dpContext** pContext, ...);
* dpResult __dpSetClippingPlanes[API]__( *dpContext** pContext, *float* cNear, *float* cFar);
* dpResult __dpSetActiveChannel[API]__( *dpContext** pContext, *unsigned int* channelId, ...);
* dpResult __dpSetFlipWarpmeshVerticesY[API]__( *dpContext** pContext, bool flip);
* dpResult __dpSetFlipWarpmeshTexcoordsV[API]__( *dpContext** pContext, bool flip);
* dpResult __dpPreDraw[API]__( *dpContext** pContext, *const dpVec3f* eyepoint, *dpVec3f** pOrientation, *dpMatrix4x4** pProjection, ...);
* dpResult __dpPreDraw1[API]__( *dpContext** pContext,*const dpVec3f* eyepoint, *dpCamera** pCamera);
* dpResult __dpPostDraw[API]__( *dpContext** pContext, ...)

### General ###

* dpResult __dpGetErrorString__( *dpContext** pContext, *char** pBuffer, *size_t* length);
* dpResult __dpGetVersion__( *int** pMajor, *int** pMinor, *int** pRevision, *int** pBuild);
* dpResult __dpGetVersionString__( *char** pBuffer, *size_t* length);

### Correction passes ###

__dpLib__ supports the following correction passes:

* dpWarpingPass: correction pass applying the warping
* dpBlendingPass: correction pass applying blending
* dpBlackLevelPass: correction pass applying black level correction
* dpSecondaryBlendingPass: correction pass applying a secondary blending
* dpDirectionalShadingPass: correction pass applying eyepoint-dependent white-point correction

Each pass can be enabled/disabled via:

* dpResult __dpSetCorrectionPass[API]__(*dpContext** pContext, *dpCorrectionPassType* pass, bool enabled);

The intensity of each pass can be gradually changed between 0 and 1 using the following function. This allows for example to crossfade between a daytime and nighttime blend file.

* dpResult __dpSetCorrectionPass1[API]__(*dpContext** pContext, *dpCorrectionPassType* pass, float value);

See [dpLib.h](../include/dpLib.h) for a more detailed function description.

## pluginID ##

The __pluginId__ necessary for creating the *dpContext* is a specific number to license your plugin via dpLib.
dpLib will show a watermark, if no license is present. Please contact VIOSO.com or domeprojection.com for details.

# building testcases #

We use CMake build system with ninja.
We use CMake's find_package() to locate dependencies. So check CMake -S output to see missing dependencies.

## dependencies ##

These dependencies are used by the testcases and need to be installed:
* GLFW3
* DXUT (to be removed)
* Vulkan-SDK, including SPIRV compiler
These dependencies come bundled in the external folder, no need to install:
* DirectX 9 SDK 
* glad
* GLM
* STB image

### Windows ###

Use Visual Studio 2022
In Visual Studio, open the base folder as "CMake project"
Install vcpkg to manage 
See, if there are dependencies missing and install them in case.
Configure a install destination and then install (cmake --install) will create a distributable package.

### Linux ###

Make sure you got all dependencies installes. Here are the commands to install on Ubuntu 22
wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.3.290-jammy.list https://packages.lunarg.com/vulkan/1.3.290/lunarg-vulkan-1.3.290-jammy.list
sudo apt update
sudo apt upgrade
audo apt install cmake
audo apt install ninja-build
sudo apt install build-essential
sudo apt install mercurial
sudo apt install vulkan-sdk
sudo apt install libglfw3-dev

Make sure you have cmake and ninja installed.
Cd to your base path.

cmake -S . -B ./out/build/release -G Ninja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE=Release
cmake --build ./out/build/release --config Release

Demo applications are in:
./out/build/release
All dependencies are copied to allow the applications to run.
