///
/// Copyright (C) 2018 domeprojection.com GmbH.
/// All rights reserved.
/// Contact: domeprojection.com GmbH (support@domeprojection.com)
///
/// This file is part of the dpLib.
///

#ifndef _DPLIB_H_
#define _DPLIB_H_

#include "dpTypes.h"

#ifdef DPLIB_WINDOWS
struct IDirect3DDevice9;
struct IDirect3DTexture9;
struct IDirect3DSurface9;

struct ID3D11Device;
struct ID3D11DeviceContext;
struct ID3D11ShaderResourceView;
#endif

#ifdef __cplusplus
extern "C" {
#endif

///
/// general interface
///

/// This function returns a short error description. Use this method to get a more detailed description of the last
/// error occured.
/// @param pContext A pointer to the context
/// @param pBuffer  A pointer to a buffer the error description gets copied into
/// @param length   The size of the buffer
/// @return This function returns dpNoError on success. If pContext or pBuffer is NULL dpInvalidPointer is returned.
DPLIB_API dpResult dpGetErrorString(dpContext* pContext, char* pBuffer, size_t length);

DPLIB_API dpResult dpGetVersion(int* pMajor, int* pMinor, int* pRevision, int* pBuild);
DPLIB_API dpResult dpGetVersionString(char* pBuffer, size_t length);

#ifdef DPLIB_WINDOWS

///
/// DirectX 9 interface
///

/// This function creates a new context, which is needed for using the correction library
/// @param ppContext The address of a pointer variable that receives the pointer to a newly created dpContext
/// @param pDevice   A pointer to an IDirect3DDevice9 which is used for creating global resources during 
///                  context creation.
/// @param pluginId  The ID given from domeprojection.com
/// @return The function return dpNoError when the context was created successful. If ppContext or pDevice is NULL
///         this method return dpInvalidPointer. If dpD3DError is returned the internal used resources creation
///         has failed.
DPLIB_API dpResult dpCreateContextD3D9(dpContext** ppContext, IDirect3DDevice9* pDevice, unsigned int pluginId);

/// This function destroys a dpContext and frees all internal used memory. You should always call this function
/// to avoid memory leaks.
/// @param pContext A pointer to the context to destroy
/// @param pDevice  A pointer to an IDirect3DDevice9 which was used for context creation
/// @return The function returns dpNoError when the context was destroyed successful. If pContext or pDevice is
///         NULL dpInvalidPointer is returned.
DPLIB_API dpResult dpDestroyContextD3D9(dpContext* pContext, IDirect3DDevice9* pDevice);

/// This function configures the given context. You should call this method before any call to dpSetActiveChannel,
/// dpPreDraw or dpPostDraw.
/// @param pContext A pointer to the context to configure
/// @param filename The name of the configuration file
/// @return This function returns dpNoError if the configuration was successful. If pContext is NULL dpInvalidPointer
///         is returned. If the configuration file not exists dpFileNotFound is returned. In case the configuration
///         file is not valid xml or does not fit the configuration file specification dpInvalidData is returned.
DPLIB_API dpResult dpLoadConfigurationFromFileD3D9(dpContext* pContext, const char* filename);

// This function sets the internal used clipping planes used for calculating the projection matrices.
// @param pContext A pointer to the context the clipping planes should set
// @param cNear    The near clipping plane
// @param cFar     The far clipping plane
// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetClippingPlanesD3D9(dpContext* pContext, float cNear, float cFar);

/// This function sets the correction passes for the active channel for the given context.
/// @param pContext  A pointer to the context
/// @param pass      The correction pass type to enable/disable
/// @param enabled   The new state for the given correction pass
/// @param value     A gradual value for applying the correction pass. Usually a value in [0..1]
/// @return When the correction pass was set successful dpNoError is returned. If pContext is NULL dpInvalidPointer is
///         returned. If no configuration is available for the active channel dpInvalidData is returned.
DPLIB_API dpResult dpSetCorrectionPassD3D9(dpContext* pContext, dpCorrectionPassType pass, bool enabled);
DPLIB_API dpResult dpSetCorrectionPassD3D9_1(dpContext* pContext, dpCorrectionPassType pass, float value);

/// This function sets the behaviour during loading the warpmesh vertices.
/// @param pContext  A pointer to the context
/// @param flip If true the warpmesh vetices will be flipped in y during loading.
/// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetFlipWarpmeshVerticesYD3D9(dpContext* pContext, bool flip);

/// This function sets the behaviour during loading the warpmesh texcoords.
/// @param pContext  A pointer to the context
/// @param flip If true the warpmesh texcoords wiill be flipped in v during loading.
/// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetFlipWarpmeshTexcoordsVD3D9(dpContext* pContext, bool flip);

/// This function sets the active channel for the given context. Call this function when ever the engine starts
/// rendering a new channel.
/// @param pContext  A pointer to the context
/// @param channelId The channel to set active
/// @param pDevice   A pointer to an IDirect3DDevice9
/// @param width     The width of the currently set channel
/// @param height    The height of the currently set channel
/// @return When the channel was set succesful dpNoError is returned. If pContext or pDevice is NULL dpInvalidPointer is
///         returned. If no configuration is available for the channel dpInvalidData is returned. When any resource
///         creation fails dpD3DError is returned.
DPLIB_API dpResult dpSetActiveChannelD3D9(dpContext* pContext, unsigned int channelId, IDirect3DDevice9* pDevice, unsigned int width, unsigned int height);

/// This function initializes the correction library for rendering the currently set channel. You should call this method
/// right before the engine starts rendering the scene.
/// @param pContext     A pointer to the context
/// @param eyepoint     The currently set eyepoint in simulator space
/// @param pOrientation A pointer to the currently set orientation (heading,pitch,bank). Can be NULL
/// @param pProjection  A pointer to the currently set projection matrix. Can be NULL
/// @param pCamera      A pointer to a dpCamera struct which gets filled with the camera configuration to be used.
/// @param pDevice      A pointer to an IDirect3DDevice9
/// @return This method returns dpNoError. If pContext is NULL dpInvalidPointer is returned.
DPLIB_API dpResult dpPreDrawD3D9(dpContext* pContext, const dpVec3f eyepoint, dpVec3f* pOrientation, dpMatrix4x4* pProjection, IDirect3DDevice9* pDevice);
DPLIB_API dpResult dpPreDrawD3D9_1(dpContext* pContext, const dpVec3f eyepoint, dpCamera* pCamera, IDirect3DDevice9* pDevice);

/// This function applies the correction. You should call this function after the engine has rendered the scene.
/// @param pContext A pointer to the context
/// @param pTexture A pointer to the texture containing the scene to be corrected
/// @param pSurface A pointer to a surface containing the scene to be corrected
/// @param pDevice  A pointer to an IDirect3DDevice9
/// @return When the correction was applied successful dpNoError is returned. If pContext, pDevice, pTexture
/// or pSurface is NULL dpInvalidPointer is returned. If the surface width/height is 0 dpInvalidData is
/// returned. On any error using the IDirect3DDevice9 pointer dpD3DError is returned.
DPLIB_API dpResult dpPostDrawD3D9(dpContext* pContext, IDirect3DTexture9* pTexture, IDirect3DDevice9* pDevice);
DPLIB_API dpResult dpPostDrawD3D9_1(dpContext* pContext, IDirect3DSurface9* pSurface, IDirect3DDevice9* pDevice);

/// This function returns the current warpmesh
/// @param pContext  A pointer to the context
/// @param channelId The channel the warpmesh should be returned
/// @param pMesh     A pointer to the mesh the warpmesh will copied into
/// @return This methos returns dpNoError if the warpmesh was copied successfully. If pContext or pMesh is NULL dpInvalidPointer is returned.
DPLIB_API dpResult dpGetWarpmeshD3D9(dpContext* pContext, unsigned int channelId, dpMesh* pMesh);





/// This function creates a new context, which is needed for using the correction library
/// @param ppContext The address of a pointer variable that receives the pointer to a newly created dpContext
/// @param pDevice   A pointer to an ID3D11Device which is used for creating global resources during 
///                  context creation.
/// @param pluginId  The ID given from domeprojection.com
/// @return The function return dpNoError when the context was created successful. If ppContext or pDevice is NULL
///         this method return dpInvalidPointer. If dpD3DError is returned the internal used resources creation
///         has failed.
///
/// During context creation the following resources are created:
/// - one vertex shader
/// - three pixel shader
/// - one input layout
/// - one sampler state
/// - one shader resource view
/// - one depth stencil state
/// - one blend state
/// - one constant buffer
DPLIB_API dpResult dpCreateContextD3D11(dpContext** ppContext, ID3D11Device* pDevice, unsigned int pluginId);

/// This function destroys a dpContext and frees all internal used memory. You should always call this function
/// to avoid memory leaks.
/// @param pContext A pointer to the context to destroy
/// @return The function returns dpNoError when the context was destroyed successful. If pContext or pDevice is
///         NULL dpInvalidPointer is returned.
DPLIB_API dpResult dpDestroyContextD3D11(dpContext* pContext);

/// This function configures the given context. You should call this method before any call to dpSetActiveChannel,
/// dpPreDraw or dpPostDraw.
/// @param pContext A pointer to the context to configure
/// @param filename The name of the configuration file
/// @return This function returns dpNoError if the configuration was successful. If pContext is NULL dpInvalidPointer
///         is returned. If the configuration file not exists dpFileNotFound is returned. In case the configuration
///         file is not valid xml or does not fit the configuration file specification dpInvalidData is returned.
DPLIB_API dpResult dpLoadConfigurationFromFileD3D11(dpContext* pContext, const char* filename);

/// This function sets the internal used clipping planes used for calculating the projection matrices.
/// @param pContext A pointer to the context the clipping planes should set
/// @param cNear    The near clipping plane
/// @param cFar     The far clipping plane
/// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetClippingPlanesD3D11(dpContext* pContext, float cNear, float cFar);

/// This function sets the active channel for the given context. Call this function when ever the engine starts
/// rendering a new channel.
/// @param pContext  A pointer to the context
/// @param channelId The channel to set active
/// @param pDevice   A pointer to an ID3D11Device
/// @param width     The width of the currently set channel
/// @param height    The height of the currently set channel
/// @return When the channel was set succesful dpNoError is returned. If pContext or pDevice is NULL dpInvalidPointer is
///         returned. If no configuration is available for the channel dpInvalidData is returned. When any resource
///         creation fails dpD3DError is returned.
///
/// The first time this method gets called for a channel all necessary resources are getting created
/// - one shader resource view
/// - two vertex buffers
/// - one index buffer
DPLIB_API dpResult dpSetActiveChannelD3D11(dpContext* pContext, unsigned int channelId, ID3D11Device* pDevice, unsigned int width, unsigned int height);

/// This function sets the correction passes for the active channel for the given context.
/// @param pContext  A pointer to the context
/// @param pass      The correction pass type to enable/disable
/// @param enabled   The new state for the given correction pass
/// @param value     A gradual value for applying the correction pass. Usually a value in [0..1]
/// @return When the correction pass was set successful dpNoError is returned. If pContext is NULL dpInvalidPointer is
///         returned. If no configuration is available for the active channel dpInvalidData is returned.
DPLIB_API dpResult dpSetCorrectionPassD3D11(dpContext* pContext, dpCorrectionPassType pass, bool enabled);
DPLIB_API dpResult dpSetCorrectionPassD3D11_1(dpContext* pContext, dpCorrectionPassType pass, float value);

/// This function sets the behaviour during loading the warpmesh vertices.
/// @param pContext  A pointer to the context
/// @param flip If true the warpmesh vetices will be flipped in y during loading.
/// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetFlipWarpmeshVerticesYD3D11(dpContext* pContext, bool flip);

/// This function sets the behaviour during loading the warpmesh texcoords.
/// @param pContext  A pointer to the context
/// @param flip If true the warpmesh texcoords wiill be flipped in v during loading.
/// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetFlipWarpmeshTexcoordsVD3D11(dpContext* pContext, bool flip);

/// This function initializes the correction library for rendering the currently set channel. You should call this method
/// right before the engine starts rendering the scene.
/// @param pContext     A pointer to the context
/// @param eyepoint     The currently set eyepoint in simulator space
/// @param pOrientation A pointer to the currently set orientation (heading,pitch,bank). Can be NULL
/// @param pProjection  A pointer to the currently set projection matrix. Can be NULL
/// @return This method returns dpNoError. If pContext is NULL dpInvalidPointer is returned.
DPLIB_API dpResult dpPreDrawD3D11(dpContext* pContext, const dpVec3f eyepoint, dpVec3f* pOrientation, dpMatrix4x4* pProjection);
DPLIB_API dpResult dpPreDrawD3D11_1(dpContext* pContext, const dpVec3f eyepoint, dpCamera* pCamera);

/// This function applies the correction. You should call this function after the engine has rendered the scene.
/// @param pContext A pointer to the context
/// @param pTexture A pointer to the texture containing the scene to be corrected
/// @param pDeviceContext  A pointer to the ID3D11DeviceContext to be used for rendering
/// @return When the correction was applied successful dpNoError is returned. If pContext, pDeviceContext or pTexture
/// is NULL dpInvalidPointer is returned. On any error using the ID3D11DeviceContext pointer dpD3DError is returned.
///
/// When using correction type dpDynamic every call updates the vertex mesh. For this the vertex buffer resource
/// have to be mapped to get cpu access to the memory. For static correction no update is needed.
DPLIB_API dpResult dpPostDrawD3D11(dpContext* pContext, ID3D11ShaderResourceView* pTexture, ID3D11DeviceContext* pDeviceContext);

#endif



/// This function creates a new context, which is needed for using the correction library
/// @param ppContext The address of a pointer variable that receives the pointer to a newly created dpContext
/// @param pluginId  The ID given from domeprojection.com
/// @param target    This parameter specifies how the texture in dpPostDrawOpenGL will be interpreted. For using GL_TEXTURE_2D
///                  set target to dpTextureTarget2D, for using GL_TEXTURE_RECTANGLE use dpTextureTargetRectangle.
/// @return The function return dpNoError when the context was created successful. If ppContext is NULL
///         this method return dpInvalidPointer.
///
/// During context creation the following resources are created:
/// - two vertex shader
/// - two pixel shader
/// - one texture
DPLIB_API dpResult dpCreateContextOpenGL(dpContext** ppContext, unsigned int pluginId, dpTextureTarget target = dpTextureTarget2D);

/// This function destroys a dpContext and frees all internal used memory. You should always call this function
/// to avoid memory leaks.
/// @param pContext A pointer to the context to destroy
/// @return The function returns dpNoError when the context was destroyed successful. If pContext or pDevice is
///         NULL dpInvalidPointer is returned.
DPLIB_API dpResult dpDestroyContextOpenGL(dpContext* pContext);

/// This function configures the given context. You should call this method before any call to dpSetActiveChannel,
/// dpPreDraw or dpPostDraw.
/// @param pContext A pointer to the context to configure
/// @param filename The name of the configuration file
/// @return This function returns dpNoError if the configuration was successful. If pContext is NULL dpInvalidPointer
///         is returned. If the configuration file not exists dpFileNotFound is returned. In case the configuration
///         file is not valid xml or does not fit the configuration file specification dpInvalidData is returned.
DPLIB_API dpResult dpLoadConfigurationFromFileOpenGL(dpContext* pContext, const char* filename);

/// This function sets the internal used clipping planes used for calculating the projection matrices.
/// @param pContext A pointer to the context the clipping planes should set
/// @param cNear    The near clipping plane
/// @param cFar     The far clipping plane
/// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetClippingPlanesOpenGL(dpContext* pContext, float cNear, float cFar);

/// This function sets the active channel for the given context. Call this function when ever the engine starts
/// rendering a new channel.
/// @param pContext  A pointer to the context
/// @param channelId The channel to set active
/// @param width     The width of the currently set channel
/// @param height    The height of the currently set channel
/// @return When the channel was set succesful dpNoError is returned. If pContext is NULL dpInvalidPointer is
///         returned. If no configuration is available for the channel dpInvalidData is returned.
///
/// The first time this method gets called for a channel all necessary resources are getting created
/// - two textures
/// - two vertex array objects with 3 vertex buffer objects each
DPLIB_API dpResult dpSetActiveChannelOpenGL(dpContext* pContext, unsigned int channelId, unsigned int width, unsigned int height);

/// This function sets the correction passes for the active channel for the given context.
/// @param pContext  A pointer to the context
/// @param pass      The correction pass type to enable/disable
/// @param enabled   The new state for the given correction pass
/// @param value     A gradual value for applying the correction pass. Usually a value in [0..1]
/// @return When the correction pass was set successful dpNoError is returned. If pContext is NULL dpInvalidPointer is
///         returned. If no configuration is available for the active channel dpInvalidData is returned.
DPLIB_API dpResult dpSetCorrectionPassOpenGL(dpContext* pContext, dpCorrectionPassType pass, bool enabled);
DPLIB_API dpResult dpSetCorrectionPassOpenGL_1(dpContext* pContext, dpCorrectionPassType pass, float value);

/// This function sets the behaviour during loading the warpmesh vertices.
/// @param pContext  A pointer to the context
/// @param flip If true the warpmesh vetices will be flipped in y during loading.
/// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetFlipWarpmeshVerticesYOpenGL(dpContext* pContext, bool flip);

/// This function sets the behaviour during loading the warpmesh texcoords.
/// @param pContext  A pointer to the context
/// @param flip If true the warpmesh texcoords wiill be flipped in v during loading.
/// @return This function returns dpNoError on success. If pContext is NULL dpInvalidPointer will be returned.
DPLIB_API dpResult dpSetFlipWarpmeshTexcoordsVOpenGL(dpContext* pContext, bool flip);

/// This function initializes the correction library for rendering the currently set channel. You should call this method
/// right before the engine starts rendering the scene.
/// @param pContext     A pointer to the context
/// @param eyepoint     The currently set eyepoint in simulator space
/// @param pOrientation A pointer to the currently set orientation (heading,pitch,bank). Can be NULL
/// @param pProjection  A pointer a camera which gets filled with camera parameters to use by the engine. Can be NULL
/// @param pCamera  A pointer to the currently set projection matrix. Can be NULL
/// @return This method returns dpNoError. If pContext is NULL dpInvalidPointer is returned.
DPLIB_API dpResult dpPreDrawOpenGL(dpContext* pContext, const dpVec3f eyepoint, dpVec3f* pOrientation, dpMatrix4x4* pProjection);
DPLIB_API dpResult dpPreDrawOpenGL_1(dpContext* pContext, const dpVec3f eyepoint, dpCamera* pCamera);

/// This function applies the correction. You should call this function after the engine has rendered the scene.
/// @param pContext A pointer to the context
/// @param texture Texture target containing the scene to be corrected (interpreted as GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE,
///                depends on context creation parameter)
/// @param textureRect Texture target containing the scene to be corrected (GL_TEXTURE_RECTANGLE expected)
/// @return When the correction was applied successful dpNoError is returned. If pContext, texture
/// NULL dpInvalidPointer is returned.
///
/// When using correction type dpDynamic every call updates the vertex mesh. For this the vertex buffer resource
/// have to be mapped to get cpu access to the memory. For static correction no update is needed.
DPLIB_API dpResult dpPostDrawOpenGL(dpContext* pContext, unsigned int texture);


#ifdef __cplusplus
}
#endif

#endif // _DPLIB_H_
