// Raytrix API LF Camera Example 01
/*
	This example demonstrates how to initialize, open and capture from 
	a Raytrix camera. 
*/

#include <SDKDDKVer.h>
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <conio.h>

// The Raytrix Core library
#include "Rx.Core\RxCore.h"

// The Raytrix Light Field API
#include "Rx.ApiLF\Rx.ApiLF.h"

// Include CLUViz Tool DLL to display/load/save images.
#include "Rx.CluViz.Core.CluVizTool\CvCluVizTool.h"

using namespace Rx;
using namespace Rx::ApiLF;

int _tmain(int argc, _TCHAR* argv[])
{
	int iView = 0;
	unsigned uImgID = 0;
	int iDev, iDevCnt;
	unsigned uDeviceID, uMajor, uMinor, uCameraCount, uCamID, uCapImgID;
	unsigned uLensCnt, uLensSetCnt, uLens, uLensSet;
	double dValue, dTime;
	bool bEnd = false;

	CRxString sxPath, sxFile;
	CRxString sxDevName, sxValue;
	CRxImage xImage;

	// Initialize CLUVizTool
	CLUViz::Tool::Init();	
	// Create an image view
	CLUViz::Tool::CreateViewImage( iView, 600, 100, 800, 600, "Image" );

	try
	{
		// Open a console that displays output from the LF API
		Rx::ApiLF::RxLogConsoleShow();

		// Initialize Raytrix Library
		printf("Initializing API...\n");
		RX_TRY( RxInit(true, "", "", 0) );

		////////////////////////////////////////////////////////////////////
		// List available CUDA devices and select one
		RX_TRY( RxCudaDeviceCount(iDevCnt) );
		for ( iDev = 0; iDev < iDevCnt; ++iDev )
		{
			RX_TRY( RxCudaDeviceProp(iDev, sxDevName, uMajor, uMinor) );
			printf( "CUDA Device %d: %s (%d.%d)\n", iDev, (const char *) sxDevName, uMajor, uMinor );
		}

		// Automatic selection if no device ID or a negative device ID is given.
		RX_TRY( RxCudaSelectDevice() );

		// Get information on selected CUDA device
		RX_TRY( RxGetPar( EPar::Cuda_DeviceName, sxDevName ) );
		RX_TRY( RxGetPar( EPar::Cuda_DeviceID, uDeviceID ) );
		RX_TRY( RxGetPar( EPar::Cuda_CapaMajor, uMajor ) );
		RX_TRY( RxGetPar( EPar::Cuda_CapaMinor, uMinor ) );

		printf( "Selected CUDA Device: %d, %s, (%d.%d)\n", uDeviceID, (const char *) sxDevName, uMajor, uMinor );
		printf( "\n\n" );

		////////////////////////////////////////////////////////////////////
		// Initialize cameras

		printf( "Initializing camera drivers..." );
		RX_TRY( RxCamDriverInit() );
		printf( "done.\n" );

		printf( "Registering cameras..." );
		RX_TRY( RxCamRegister() );
		printf( "done.\n" );

		////////////////////////////////////////////////////////////////////
		// Get information on available cameras

		// Number of cameras available
		RX_TRY( RxGetPar(EPar::Cam_Count, uCameraCount) );

		if ( uCameraCount == 0 )
		{
			printf( "No cameras available. Press any key to end...\n" );
			_getch();
			return -1;
		}
		printf( "Number of cameras available: %d\n", uCameraCount );


		////////////////////////////////////////////////////////////////////
		// Get information on available camera calibration settings

		// Work with camera 0
		uCamID = 0;

		printf( "Opening camera 0..." );
		// Before the calibration database for a camera can be accessed
		// the camera has to be opened.
		RX_TRY( RxCamOpen(uCamID) );
		printf( "done.\n" );

		printf( "______________________________________________\n");
		printf( "Camera %d:\n", uCamID );

		RX_TRY( RxCamGetPar(uCamID, EPar::Cam_Type, sxValue) );
		printf( ">> Type: %s\n", sxValue.ToCString() );

		RX_TRY( RxCamGetPar(uCamID, EPar::Cam_ID, sxValue) );
		printf( ">> ID  : %s\n", sxValue.ToCString() );
		
		printf( "\n\n" );


		printf( "Available camera calibrations:\n");
		printf( "______________________________\n");

		// Number of lenses in calibration database
		RX_TRY( RxCamGetPar( uCamID, EPar::CamCal_LensCnt, uLensCnt ) );
		printf("Lens count: %d\n", uLensCnt );

		for ( uLens = 0; uLens < uLensCnt; ++uLens )
		{
			printf( "_______________________________\n" );
			printf( "Lens %d:\n", uLens );

			// Select lens with index uLens
			RX_TRY( RxCamSetPar( uCamID, EPar::CamCal_LensIdx, uLens ) );

			// Get the lens name
			RX_TRY( RxCamGetPar( uCamID, EPar::CamCal_LensName, sxValue ) );
			printf("> Lens name: %s\n", sxValue.ToCString() );

			// Get the lens ID
			RX_TRY( RxCamGetPar( uCamID, EPar::CamCal_LensID, sxValue ) );
			printf("> Lens ID: %s\n", sxValue.ToCString() );

			// Get number lens settings for selected lens
			// A lens setting consists of a f-stop and focus setting.
			RX_TRY( RxCamGetPar( uCamID, EPar::CamCal_LensSetCnt, uLensSetCnt ) );

			for ( uLensSet = 0; uLensSet < uLensSetCnt; ++uLensSet )
			{
				printf( "> _______________________________\n" );
				printf( "> Lens setting %d:\n", uLens );

				// Select the lens setting with index uLensSet
				RX_TRY( RxCamSetPar( uCamID, EPar::CamCal_LensSetIdx, uLensSet ) );

				// Get F-Stop value
				RX_TRY( RxCamGetPar( uCamID, EPar::CamCal_LensSetFStop, dValue ) );
				printf(">> FStop: %g\n", dValue );

				// Get Focus value
				RX_TRY( RxCamGetPar( uCamID, EPar::CamCal_LensSetFocus, dValue ) );
				printf(">> Focus: %g\n", dValue );
			}
			printf("\n");
		}

		/////////////////////////////////////////////////////////////////
		// Capture images from camera

		// Before capturing is started, select a lens and a lens setting
		// from the calibration database.
		// IMPORTANT: 
		//		If the lens or lens setting is changed AFTER
		//		RxCamStartCapture() is called, the function 
		//		RxCamCalibUpdate() has to be called to make the new
		//		calibration setting active.

		// Select lens with index 0
		RX_TRY( RxCamSetPar( uCamID, EPar::CamCal_LensIdx, unsigned(0) ) );
		// Select the lens setting with index 0
		RX_TRY( RxCamSetPar( uCamID, EPar::CamCal_LensSetIdx, unsigned(0) ) );

		// Select camera trigger mode
		RX_TRY( RxCamSetPar( uCamID, EPar::Cam_TriggerMode, (unsigned) ECameraTriggerMode::Software_SnapShot ));

		// Now start capturing images
		printf("Starting capture...");
		RX_TRY( RxCamStartCapture(uCamID, uCapImgID) );
		printf("done.\n\n");

		printf("\n\n");
		printf("Set camera parameter\n");
		printf("____________________\n");

		// Get the current camera exposure
		RX_TRY( RxCamGetPar(uCamID, EPar::Cam_Exposure, dValue) );
		//RxCamGetPar(uCamID, EPar::Cam_Exposure, dValue);
		printf("Init Exposure: %g\n", dValue);

		// Set the camera exposure in milliseconds
		RX_TRY( RxCamSetPar(uCamID, EPar::Cam_Exposure, 300.0) );

		// Depending on the camera and other settings, the exposure
		// time set in the previous step may not be exactly available.
		// Read the exposure time again to see what the actual value is.
		RX_TRY( RxCamGetPar(uCamID, EPar::Cam_Exposure, dValue) );
		printf("New Exposure: %g\n", dValue);


		// The variable uCapImgID now contains the ray image handle 
		// of the ray image the camera captures into.

		int iKey;
		bool bDoCapture = true;
		bool bUpdateImage = false;
		double dFocus = 0.5;

		// Loop until the user ends the program
		while ( !bEnd )
		{
			if ( bDoCapture )
			{
				bDoCapture = false;

				dTime = RxGetTime();
				// Capture an image from the camera
				if ( !RxCamDoCapture(uCamID) )
				{
					CRxString sxError;
					int iErr = RxGetLastError(sxError);
					if ( iErr == EWarning::CAMERA_CAPTURE_NOIMAGE )
					{
						printf("No image available.\n");
					}
					else
					{
						printf("Error: %s\n", sxError.ToCString());
					}
				}
				else
				{
					dTime = RxGetTime() - dTime;
					printf( "Capture time: %gms\n", dTime );
					bUpdateImage = true;
				}
			}

			if ( bUpdateImage )
			{
				bUpdateImage = false;

				// Focus ray image to plane at depth dDepth
				RX_TRY( RxSetPar( EPar::Focus_Focus, dFocus ));
				RX_TRY( RxFocusOnPlane( ) );

				// Get focused image from CUDA device
				RX_TRY( RxGetImage( EImgID::Focus, xImage ) );

				// Display the image
				CLUViz::Tool::ViewSetImage( iView, &xImage );
			}

			printf( "\nMenu:\n");
			printf( "'c': Capture new image\n" );
			printf( "'+', '-': Change focus\n" );
			printf( "'q': End\n\n" );

			iKey = _getch();
			switch( iKey )
			{
			case 'c':
				bDoCapture = true;
				break;

			case '+':
				dFocus += 0.05;
				bUpdateImage = true;
				break;

			case '-':
				dFocus -= 0.05;
				bUpdateImage = true;
				break;

			case 'q':
				bEnd = true;
				break;
			}

			if ( dFocus < 0.0 )
				dFocus = 0.0;
			else if ( dFocus >= 1.0 )
				dFocus = 0.95;
		}

		printf("Stopping camera capture...");
		// Stop capturing
		RxCamStopCapture( uCamID );
		printf("done.\n");

		printf("Closing camera...");
		// Close camera
		RxCamClose( uCamID );
		printf("done.\n");
	}
	catch( int iError )
	{
		printf("Press any key to end program...\n");
		_getch();
		return iError;
	}

	printf("Closing CLUViz Tool...");
	// Close all CLUViz Windows and free internally used memory
	CLUViz::Tool::Finalize();
	printf("done.\n");

	printf("Closing Raytrix API...");
	// Close Raytrix API, free all memory on host and CUDA device
	// and close all open cameras.
	RxFinalize();
	printf("done.\n");

	return 0;
}

