//********************************************************************************************************************************
//*                                                                                                                              *
//*     Image Recognition Library 1.0.40.49 © 3delite 2011-2021                                                                  *
//*     See Image Recognition Library ReadMe.txt for details                                                                     *
//*                                                                                                                              *
//* Licenses available for usage of this library:                                                                                *
//* Freeware License: €25                                                                                                        *
//*     http://www.shareit.com/product.html?productid=300983850                                                                  *
//* Shareware License: €50                                                                                                       *
//*     http://www.shareit.com/product.html?productid=300486940                                                                  *
//* Commercial License: €250                                                                                                     *
//*     http://www.shareit.com/product.html?productid=300486939                                                                  *
//*                                                                                                                              *
//*     https://www.3delite.hu/Object%20Pascal%20Developer%20Resources/ImageRecognitionLibrary.html                              *
//*                                                                                                                              *
//* If you have any questions or enquiries please mail: 3delite@3delite.hu                                                       *
//*                                                                                                                              *
//* Good coding! :)                                                                                                              *
//* 3delite                                                                                                                      *
//********************************************************************************************************************************

#pragma once

#ifdef _WIN32 // Windows
//* .dll file name
#define FILENAME_DLL_IMAGE_RECOGNITION_LIBRARY	"ImageRecognition.dll"
#define IRLIBCALL __stdcall

#define GETIMAGERECOGNITIONLIBFUNCTION(f) *((void**)&f) = GetProcAddress(ImageRecognitionLibraryDLLHandle, #f)

//* Exported function names (Windows)
#define NAME_ImageRecognition_CreateObject					"ImageRecognition_CreateObject"
#define NAME_ImageRecognition_FreeObject					"ImageRecognition_FreeObject"
#define NAME_ImageRecognition_Compare						"ImageRecognition_Compare"
#define NAME_ImageRecognition_FreeResult					"ImageRecognition_FreeResult"
#define NAME_ImageRecognition_CreateObjectFromBitmapHandle	"ImageRecognition_CreateObjectFromBitmapHandle"
#define NAME_ImageRecognition_CreateObjectFromMemory        "ImageRecognition_CreateObjectFromMemory"
#define NAME_ImageRecognition_OpenCLGetPlatform             "ImageRecognition_OpenCLGetPlatform"
#define NAME_ImageRecognition_OpenCLGetPlatformDevice       "ImageRecognition_OpenCLGetPlatformDevice"
#define NAME_ImageRecognition_OpenCLInit                    "ImageRecognition_OpenCLInit"
#define NAME_ImageRecognition_OpenCLFree                    "ImageRecognition_OpenCLFree"
#define NAME_ImageRecognition_OpenCLSetSearchIn             "ImageRecognition_OpenCLSetSearchIn"
#define NAME_ImageRecognition_OpenCLSetSearchFor            "ImageRecognition_OpenCLSetSearchFor"
#define NAME_ImageRecognition_OpenCLPerformSearch           "ImageRecognition_OpenCLPerformSearch"
#define NAME_ImageRecognition_CreateSearchQueue				"ImageRecognition_CreateSearchQueue"
#define NAME_ImageRecognition_FreeSearchQueue				"ImageRecognition_FreeSearchQueue"
#define NAME_ImageRecognition_AddSearchWork					"ImageRecognition_AddSearchWork"
#define NAME_ImageRecognition_FreeSearchQueueResult			"ImageRecognition_FreeSearchQueueResult"
#define NAME_ImageRecognition_AbortSearchQueue				"ImageRecognition_AbortSearchQueue"
#define NAME_ImageRecognition_CreateLoadQueue               "ImageRecognition_CreateLoadQueue"
#define NAME_ImageRecognition_FreeLoadQueue                 "ImageRecognition_FreeLoadQueue"
#define NAME_ImageRecognition_AddLoadWork                   "ImageRecognition_AddLoadWork"
#define NAME_ImageRecognition_AddLoadWorkBitmapHandle       "ImageRecognition_AddLoadWorkBitmapHandle"
#define NAME_ImageRecognition_FreeLoadQueueResult           "ImageRecognition_FreeLoadQueueResult"
#define NAME_ImageRecognition_AbortLoadQueue				"ImageRecognition_AbortLoadQueue"

#endif

//*	Error codes
#define IR_OK							0
#define IR_ERROR_UNKNOWN				1
#define IR_ERROR_NOT_ENOUGH_MEMORY		2
#define IR_ERROR_LOADING				3
#define IR_ERROR_OBJECT					4
#define IR_ERROR_DIMENSIONS				5
#define IR_ERROR_NOT_AVAILABLE			6
#define IR_ERROR_OCL_NOT_AVAILABLE      7
#define IR_ERROR_OCL_NOT_INITIALIZED    8
#define IR_ERROR_OCL_NO_SEARCH_IN_SET   9
#define IR_ERROR_OCL_NO_SEARCH_FOR_SET  10
#define IR_ERROR_NO_SEARCH_QUEUE_SET	11
#define IR_ERROR_OCL_SET_SEARCH_IN		12
#define IR_ERROR_OCL_SET_SEARCH_FOR		13
#define IR_ERROR_NO_LOAD_QUEUE_SET		14

//* Status types
#define IR_STATUS_PROGRESS			1

//* Compare type modes
#define IR_COMPARE_TYPE_EXACT				0
#define IR_COMPARE_TYPE_RELATIVE_ARGB		1
#define IR_COMPARE_TYPE_RELATIVE_AHSL       2
#define IR_COMPARE_TYPE_RELATIVE_ARGB_ALPHA 3
#define IR_COMPARE_TYPE_RELATIVE_AHSL_ALPHA 4

//* Queue modes
#define IR_SEARCH_MODE_CPU		0
#define IR_SEARCH_MODE_OPENCL	1
#define IR_SEARCH_MODE_ANY		2

//* Queue threads
#define IR_THREAD_PRIORITY_IDLE			0
#define IR_THREAD_PRIORITY_LOWEST		1
#define IR_THREAD_PRIORITY_LOWER		2
#define IR_THREAD_PRIORITY_NORMAL		3
#define IR_THREAD_PRIORITY_HIGHER		4
#define IR_THREAD_PRIORITY_HIGHEST		5
#define IR_THREAD_PRIORITY_TIMECRITICAL 6

//* Pre-process types
#define IR_PROCESS_TYPE_NONE		0
#define IR_PROCESS_TYPE_RESAMPLE    1

//* Pre-process resample modes
#define IR_RESAMPLER_BOX			0 // Box, pulse, Fourier window, 1st order (constant) b-spline
#define IR_RESAMPLER_BICUBIC		1 // Mitchell & Netravali's two-param cubic filter
#define IR_RESAMPLER_BILINEAR		2 // Bilinear filter
#define IR_RESAMPLER_BSPLINE		3 // 4th order (cubic) b-spline
#define IR_RESAMPLER_CATMULLROM		4 // Catmull-Rom spline, Overhauser spline
#define IR_RESAMPLER_LANCZOS3		5 // Lanczos3 filter

#ifdef _WIN32
#include <wtypes.h>
typedef unsigned __int64 QWORD;
#else
#include <stdint.h>
#define WINAPI
#define CALLBACK
typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint64_t QWORD;
#ifndef __OBJC__
typedef int BOOL;
#endif
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#endif

typedef void (CALLBACK TIRStatusCallback)(double Progress, int StatusType, void *User);

typedef struct {
	int Width;
	int Height;
} *PIRDimensions, TIRDimensions;

typedef struct {
	int Status;
	LPWSTR FileName;
	void *ImageObject;
	GUID ID;
	TIRDimensions OriginalDimensions;
	TIRDimensions ProcessedDimensions;
	void *User;
} *PIRObject, TIRObject;

typedef struct {
	int ProcessType;
	TIRDimensions Dimensions;
	int Resampler;
} *PIRCreateObjectParameters, TIRCreateObjectParameters;

typedef struct {
	int CompareType;
	BYTE ARGBATolerance;
	BYTE ARGBRTolerance;
	BYTE ARGBGTolerance;
	BYTE ARGBBTolerance;
	double AHSLATolerance;
	double AHSLHTolerance;
	double AHSLSTolerance;
	double AHSLLTolerance;
	int DifferenceTolerance;
	BOOL StretchCompare;				//* Stretch compare is experimental and very slow!
	TIRDimensions MinimalStretchSize;
	TIRDimensions MaximalStretchSize;
	int StretchResampler;
	BOOL MultipleMatches;
	BOOL MultiThreadedProcessing;
	int MultiThreadCount;				//* 0 means all available CPU cores
	TIRStatusCallback *StatusCallback;
	BOOL RotateSearch;
	float RotateSearchStartDegrees;
	float RotateSearchEndDegrees;
	float RotateSearchStepDegrees;
	BOOL SearchSorroundingPixels;
} *PIRProcessParameters, TIRProcessParameters;

typedef struct {
	DWORD X;
	DWORD Y;
} *PTPoint, TPoint;

typedef struct {
	TPoint Position;
	TIRDimensions Dimensions;
	float Angle;
	int Difference;
	float MatchPercentage;
} *PIRResultMatches, TIRResultMatches;

typedef struct {
	BOOL Success;
	int MatchCount;
	PIRResultMatches Matches;
} *PIRResult, TIRResult;

typedef struct {
	void *Instance;
	int PlatformIndex;
	int DeviceIndex;
} *PIROCLDevice, TIROCLDevice;

typedef struct {
	void *Instance;
} *PIRSearchQueue, TIRSearchQueue;

typedef void (CALLBACK TIRSearchQueueMatchCallback)(int Status, void *WorkID, TIRResult CompareResult, void *User);
typedef void (CALLBACK TIRLoadQueueCallback)(int Status, TIRObject IRObject, void* User);

typedef struct {
	PIROCLDevice OCLDevices;
	DWORD OCLDeviceCount;
	int OCLThreadPriority;
	DWORD CPUThreads;
	int CPUThreadsPriority;
	int ProcessingMode;
	TIRSearchQueueMatchCallback *SearchQueueMatchCallback;
	HWND SearchQueueMatchMessageHandle;
	int SearchQueueMatchMessageID;
	void* User;
} *PIRSearchQueueParameters, TIRSearchQueueParameters;

typedef struct {
	TIRObject IRObjectSearchIn;
	TIRObject IRObjectSearchFor;
	TIRProcessParameters Parameters;
	int SearchMode;
	BOOL AutoFreeSearchInIRObject;
	BOOL AutoFreeSearchForIRObject;
	void *WorkID;
} *PIRSearchQueueWork, TIRSearchQueueWork;

typedef struct {
	int Status;
	void *WorkID;
	TIRResult CompareResult;
	void *User;
} *PIRSearchQueueResult, TIRSearchQueueResult;

typedef struct {
	void* Instance;
} *PIRLoadQueue, TIRLoadQueue;

typedef struct {
	DWORD CPUThreads;
	int CPUThreadsPriority;
	TIRLoadQueueCallback *LoadQueueCallback;
	HWND LoadQueueMessageHandle;
	int LoadQueueMessageID;
	void* User;
} *PIRLoadQueueParameters, TIRLoadQueueParameters;

//* Exported functions
typedef int(IRLIBCALL *t_ImageRecognition_CreateObject)(LPWSTR FileName, TIRObject *IRObject, TIRCreateObjectParameters Parameters);
typedef int(IRLIBCALL *t_ImageRecognition_FreeObject)(TIRObject *IRObject);
typedef int(IRLIBCALL *t_ImageRecognition_Compare)(TIRObject IRObjectSearchIn, TIRObject IRObjectSearchFor, TIRProcessParameters Parameters, TIRResult *CompareResult, void *User);
typedef BOOL(IRLIBCALL *t_ImageRecognition_FreeResult)(TIRResult *CompareResult);
typedef int(IRLIBCALL *t_ImageRecognition_CreateObjectFromBitmapHandle)(HBITMAP BitmapHandle, TIRObject *IRObject, TIRCreateObjectParameters Parameters);
typedef int(IRLIBCALL *t_ImageRecognition_CreateObjectFromMemory)(void *Address, QWORD DataSize, TIRObject *IRObject, TIRCreateObjectParameters Parameters);
typedef LPWSTR(IRLIBCALL *t_ImageRecognition_OpenCLGetPlatform)(int PlaformIndex);
typedef LPWSTR(IRLIBCALL *t_ImageRecognition_OpenCLGetPlatformDevice)(int PlaformIndex, int DeviceIndex);
typedef TIROCLDevice(IRLIBCALL *t_ImageRecognition_OpenCLInit)(int PlaformIndex, int DeviceIndex, int CompareType, BOOL RotateSearch, int ComputeCoreCount);
typedef BOOL(IRLIBCALL *t_ImageRecognition_OpenCLFree)(TIROCLDevice *OCLDevice);
typedef int(IRLIBCALL *t_ImageRecognition_OpenCLSetSearchIn)(TIROCLDevice OCLDevice, TIRObject IRObjectSearchIn);
typedef int(IRLIBCALL *t_ImageRecognition_OpenCLSetSearchFor)(TIROCLDevice OCLDevice, TIRObject IRObjectSearchFor);
typedef int(IRLIBCALL *t_ImageRecognition_OpenCLPerformSearch)(TIROCLDevice OCLDevice, TIRProcessParameters Parameters, TIRResult *CompareResult, void *User);
typedef TIRSearchQueue(IRLIBCALL* t_ImageRecognition_CreateSearchQueue)(TIRSearchQueueParameters Parameters);
typedef int(IRLIBCALL* t_ImageRecognition_FreeSearchQueue)(TIRSearchQueue *IRSearchQueue);
typedef int(IRLIBCALL* t_ImageRecognition_AddSearchWork)(TIRSearchQueue IRSearchQueue, TIRSearchQueueWork Work);
typedef BOOL(IRLIBCALL* t_ImageRecognition_FreeSearchQueueResult)(PIRSearchQueueResult *PSearchQueueResult);
typedef int(IRLIBCALL* t_ImageRecognition_AbortSearchQueue)(TIRSearchQueue IRSearchQueue);
typedef TIRLoadQueue(IRLIBCALL* t_ImageRecognition_CreateLoadQueue)(TIRLoadQueueParameters Parameters);
typedef int(IRLIBCALL* t_ImageRecognition_FreeLoadQueue)(TIRLoadQueue*IRLoadQueue);
typedef int(IRLIBCALL* t_ImageRecognition_AddLoadWork)(TIRLoadQueue IRLoadQueue, LPWSTR FileName, TIRCreateObjectParameters Parameters, void *User);
typedef int(IRLIBCALL* t_ImageRecognition_AddLoadWorkBitmapHandle)(TIRLoadQueue IRLoadQueue, HBITMAP BitmapHandle, TIRCreateObjectParameters Parameters, void *User);
typedef BOOL(IRLIBCALL* t_ImageRecognition_FreeLoadQueueResult)(PIRObject*IRObject);
typedef int(IRLIBCALL* t_ImageRecognition_AbortLoadQueue)(TIRLoadQueue IRLoadQueue);

#ifdef __cplusplus
extern "C" {
#endif

	static HMODULE ImageRecognitionLibraryDLLHandle = NULL;
	BOOL ImageRecognitionLibraryDLLLoaded = FALSE;

	t_ImageRecognition_CreateObject ImageRecognition_CreateObject = NULL;
	t_ImageRecognition_FreeObject ImageRecognition_FreeObject = NULL;
	t_ImageRecognition_Compare ImageRecognition_Compare = NULL;
	t_ImageRecognition_FreeResult ImageRecognition_FreeResult = NULL;
	t_ImageRecognition_CreateObjectFromBitmapHandle ImageRecognition_CreateObjectFromBitmapHandle = NULL;
	t_ImageRecognition_CreateObjectFromMemory ImageRecognition_CreateObjectFromMemory = NULL;
	t_ImageRecognition_OpenCLGetPlatform ImageRecognition_OpenCLGetPlatform = NULL;
	t_ImageRecognition_OpenCLGetPlatformDevice ImageRecognition_OpenCLGetPlatformDevice = NULL;
	t_ImageRecognition_OpenCLInit ImageRecognition_OpenCLInit = NULL;
	t_ImageRecognition_OpenCLFree ImageRecognition_OpenCLFree = NULL;
	t_ImageRecognition_OpenCLSetSearchIn ImageRecognition_OpenCLSetSearchIn = NULL;
	t_ImageRecognition_OpenCLSetSearchFor ImageRecognition_OpenCLSetSearchFor = NULL;
	t_ImageRecognition_OpenCLPerformSearch ImageRecognition_OpenCLPerformSearch = NULL;
	t_ImageRecognition_CreateSearchQueue ImageRecognition_CreateSearchQueue = NULL;
	t_ImageRecognition_FreeSearchQueue ImageRecognition_FreeSearchQueue = NULL;
	t_ImageRecognition_AddSearchWork ImageRecognition_AddSearchWork = NULL;
	t_ImageRecognition_FreeSearchQueueResult ImageRecognition_FreeSearchQueueResult = NULL;
	t_ImageRecognition_AbortSearchQueue ImageRecognition_AbortSearchQueue = NULL;
	t_ImageRecognition_CreateLoadQueue ImageRecognition_CreateLoadQueue = NULL;
	t_ImageRecognition_FreeLoadQueue ImageRecognition_FreeLoadQueue = NULL;
	t_ImageRecognition_AddLoadWork ImageRecognition_AddLoadWork = NULL;
	t_ImageRecognition_AddLoadWorkBitmapHandle ImageRecognition_AddLoadWorkBitmapHandle = NULL;
	t_ImageRecognition_FreeLoadQueueResult ImageRecognition_FreeLoadQueueResult = NULL;
	t_ImageRecognition_AbortLoadQueue ImageRecognition_AbortLoadQueue = NULL;

#ifdef __cplusplus
}
#endif

BOOL InitImageRecognitionLibrary()
{
	ImageRecognitionLibraryDLLHandle = LoadLibrary(FILENAME_DLL_IMAGE_RECOGNITION_LIBRARY);
	if (NULL != ImageRecognitionLibraryDLLHandle)
	{
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_CreateObject);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_FreeObject);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_Compare);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_FreeResult);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_CreateObjectFromBitmapHandle);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_CreateObjectFromMemory);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_OpenCLGetPlatform);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_OpenCLGetPlatformDevice);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_OpenCLInit);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_OpenCLFree);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_OpenCLSetSearchIn);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_OpenCLSetSearchFor);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_OpenCLPerformSearch);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_CreateSearchQueue);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_FreeSearchQueue);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_AddSearchWork);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_FreeSearchQueueResult);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_AbortSearchQueue);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_CreateLoadQueue);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_FreeLoadQueue);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_AddLoadWork);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_AddLoadWorkBitmapHandle);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_FreeLoadQueueResult);
		GETIMAGERECOGNITIONLIBFUNCTION(ImageRecognition_AbortLoadQueue);

		if ((NULL == ImageRecognition_CreateObject)
			|| (NULL == ImageRecognition_FreeObject)
			|| (NULL == ImageRecognition_Compare)
			|| (NULL == ImageRecognition_FreeResult)
			|| (NULL == ImageRecognition_CreateObjectFromBitmapHandle)
			|| (NULL == ImageRecognition_CreateObjectFromMemory)
			|| (NULL == ImageRecognition_OpenCLGetPlatform)
			|| (NULL == ImageRecognition_OpenCLGetPlatformDevice)
			|| (NULL == ImageRecognition_OpenCLInit)
			|| (NULL == ImageRecognition_OpenCLFree)
			|| (NULL == ImageRecognition_OpenCLSetSearchIn)
			|| (NULL == ImageRecognition_OpenCLSetSearchFor)
			|| (NULL == ImageRecognition_OpenCLPerformSearch)
			|| (NULL == ImageRecognition_CreateSearchQueue)
			|| (NULL == ImageRecognition_FreeSearchQueue)
			|| (NULL == ImageRecognition_AddSearchWork)
			|| (NULL == ImageRecognition_FreeSearchQueueResult)
			|| (NULL == ImageRecognition_AbortSearchQueue)
			|| (NULL == ImageRecognition_CreateLoadQueue)
			|| (NULL == ImageRecognition_FreeLoadQueue)
			|| (NULL == ImageRecognition_AddLoadWork)
			|| (NULL == ImageRecognition_AddLoadWorkBitmapHandle)
			|| (NULL == ImageRecognition_FreeLoadQueueResult)
			|| (NULL == ImageRecognition_AbortLoadQueue)
			)
		{
			ImageRecognitionLibraryDLLLoaded = FALSE;
			}
		else
		{
			ImageRecognitionLibraryDLLLoaded = TRUE;
		}
	}

	return ImageRecognitionLibraryDLLLoaded;
}

BOOL FreeImageRecognitionLibrary()
{
	if (NULL != ImageRecognitionLibraryDLLHandle)
	{
		ImageRecognitionLibraryDLLLoaded = !FreeLibrary(ImageRecognitionLibraryDLLHandle);
	}
	return !ImageRecognitionLibraryDLLLoaded;
}

