<commit_before>/*
 * Jamoma Foundation
 * Copyright © 2008, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTFoundation.h"
#include "TTSymbolTable.h"
#include "TTEnvironment.h"
#include "TTSymbolCache.h"
#include "TTCallback.h"

// Nodelib currently requires Boost Regex, which we don't have on the iOS
#ifndef DISABLE_NODELIB
#include "TTNodeLib.h"
#include "TTPath.h"
#endif

// Unit Tests
#include "TTMatrix.h"
#include "TTMatrixArray.h"
#include "TTInterpolate.test.h"
#include "TTString.test.h"
#include "TTSymbol.test.h"
#include "TTValue.test.h"
#include "TTDictionary.test.h"
// Nodelib currently requires Boost Regex, which we don't have on the iOS
#ifndef DISABLE_NODELIB
#include "TTNodeLib.test.h"
#endif

#ifdef TT_PLATFORM_MAC
#include <dlfcn.h>
#include <sys/types.h>
#include <dirent.h>
#elif TT_PLATFORM_LINUX
#include <dlfcn.h>
#elif TT_PLATFORM_WIN
#include <ShlObj.h>
#endif

#ifdef TT_PLATFORM_MAC
//#include <Carbon/Carbon.h>
#define __COREFOUNDATION_CFMESSAGEPORT__ 1
#include <CoreFoundation/CFBundle.h>
#endif

TTString        TTFoundationBinaryPath = "";

static bool		TTFoundationHasInitialized = false;

void            TTFoundationLoadExternalClasses(void);
TTErr           TTFoundationLoadExternalClassesFromFolder(const TTString& fullpath);
TTObjectBasePtr	TTFoundationInstantiateInternalClass(TTSymbol& className, TTValue& arguments);

/****************************************************************************************************/
void TTFoundationInit(const char* pathToBinaries)
{
	if (!TTFoundationHasInitialized) {
		TTFoundationHasInitialized = true;

		if (pathToBinaries)
			TTFoundationBinaryPath = pathToBinaries;

		for (int i=0; i<kNumTTDataTypes; i++)
			TTDataInfo::addDataInfoForType(TTDataType(i));

// Regex requires Boost libraries, not available for iOS for the time-being
#ifndef DISABLE_NODELIB
		TTNodeLibInit();
#endif

		ttEnvironment = new TTEnvironment;

// Regex requires Boost libraries, not available for iOS for the time-being
//#ifndef DISABLE_NODELIB
//		TTAddressCacheInit();
//#endif

#ifdef TT_DEBUG
		TTLogMessage("JamomaFoundation (TT_DEBUG) -- Version %s", TTFOUNDATION_VERSION_STRING);
		ttEnvironment->mDebugBasic = true;
#else
		TTLogMessage("JamomaFoundation -- Version %s", TTFOUNDATION_VERSION_STRING);
#endif
		if (pathToBinaries)
			TTLogMessage("-- Path %s\n", pathToBinaries);
		else
			TTLogMessage("\n");

		// register classes -- both internal and external
		TTCallback::registerClass();
		TTMatrix::registerClass();
		TTMatrixArray::registerClass();
		TTStringTest::registerClass();
		TTSymbolTest::registerClass();
		TTValueTest::registerClass();
		TTInterpolateTest::registerClass();
        TTDictionaryTest::registerClass();
// Regex requires Boost libraries, not available for iOS for the time-being
#ifndef DISABLE_NODELIB
		TTNodeLibTest::registerClass();
#endif

		TTFoundationLoadExternalClasses();
	}
}

void TTFoundationShutdown();
void TTFoundationShutdown()
{
	// FIXME: How do we call this (i.e. TTDSPShutdown()?) -- do we need to setup an observer of some sort on the environment class?
	// TODO: we need to free singletons like the environment here!
}

/****************************************************************************************************/

void TTFoundationLoadExternalClasses(void)
{
#ifdef TT_PLATFORM_MAC
	if (!TTFoundationBinaryPath.empty()) {
		// Look in the specified folder rather than the default location
		TTString extensionsPath = TTFoundationBinaryPath;
		extensionsPath += "/Extensions";
		TTFoundationLoadExternalClassesFromFolder(extensionsPath);
	}
	else {
		OSErr		err = noErr;
		TTString	fullpath;

#define LOOK_FOR_EXTENSIONS_IN_SAME_FOLDER_AS_LIB
#ifdef LOOK_FOR_EXTENSIONS_IN_SAME_FOLDER_AS_LIB
		Dl_info		info;
		char		mainBundleStr[4096];

		if (dladdr((const void*)TTFoundationLoadExternalClasses, &info)) {
			char *c = 0;

			printf("Loaded from path = %s\n", info.dli_fname);
			strncpy(mainBundleStr, info.dli_fname, 4096);
			c = strrchr(mainBundleStr, '/');
			if (c)
				*c = 0; // chop the "/JamomaFoundation.dylib off of the path

            // store binary path
            TTFoundationBinaryPath = mainBundleStr;
		}
#else // THE OLD WAY
		// Look in the folder of the host application
		CFBundleRef mainBundle = CFBundleGetMainBundle();
		CFURLRef	mainBundleURL = CFBundleCopyBundleURL(mainBundle);
		CFStringRef mainBundlePath = CFURLCopyFileSystemPath(mainBundleURL, kCFURLPOSIXPathStyle);
		char		mainBundleStr[4096];

		CFStringGetCString(mainBundlePath, mainBundleStr, 4096, kCFStringEncodingUTF8);
		strncat(mainBundleStr, "/Contents/Jamoma/Extensions", 4096);
		mainBundleStr[4095] = 0;

		CFRelease(mainBundlePath);
#endif

		err = TTFoundationLoadExternalClassesFromFolder(mainBundleStr);
		if (!err)
			return; // if we loaded classes out of a standalone app, then we don't want to be corrupted by global extensions Redmine #348
					// it could be that you want to create a standalone with a plug-in architecture -- for now that problem is ignored.

#ifdef OLD_MAC_EXTENSIONS_PATH
		// Look in ~/Library/Application Support/Jamoma/Extensions
		err = FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
		if (!err) {
			FSRefMakePath(&ref, path, 4096);
			fullpath = (char*)path;
			fullpath += "/Jamoma/Extensions";
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}

		// Look in /Library/Application Support/Jamoma/Extensions
		err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
		if (!err) {
			FSRefMakePath(&ref, path, 4096);
			fullpath = (char*)path;
			fullpath += "/Jamoma/Extensions";
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}
#else // NEW_MAC_EXTENSIONS_PATH
	    TTFoundationLoadExternalClassesFromFolder("/usr/local/jamoma/extensions");
#endif

	}
#elif TT_PLATFORM_WIN
	TTString	fullpath;
	char		temppath[4096];
	HKEY		hKey = 0;
	LONG		lRes;
	DWORD		dwSize = sizeof(temppath);
	HRESULT		hr;
	HINSTANCE	hInstance = GetModuleHandle(NULL);

	// Look in C:\Program Files\Common Files\TTBlue\Extensions
	//hr = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, SHGFP_TYPE_CURRENT, (LPSTR)temppath);

	//if (!FAILED(hr)) {
	//	fullpath = temppath;
	//	fullpath += "\\Jamoma\\Extensions\\";
	//	lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
	//	TTFoundationLoadExternalClassesFromFolder(fullpath);
	//}

	//// TODO: Look in some user-level directory like we do on the Mac?
	//
	//// Look in the support folder of the host application
	//if (hInstance) {
	//	GetModuleFileName(hInstance, (LPSTR)temppath, 4096);
	//	if (temppath[0]) {
	//		char *s = strrchr(temppath, '\\');
	//		if (s)
	//			*s = 0;
	//		fullpath = temppath;
	//		fullpath += "\\Jamoma\\Extensions\\";
	//		lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
	//		TTFoundationLoadExternalClassesFromFolder(fullpath);
	//	}
	//}

	// get the handle on JamomaFoundation.dll
	LPCSTR moduleName = "JamomaFoundation.dll";
	HMODULE	hmodule = GetModuleHandle(moduleName);
	// get the path
	GetModuleFileName(hmodule, (LPSTR)temppath, 4096);

	if (!FAILED(hmodule)) {
		if (temppath[0]) {
			fullpath = temppath;
			// get support folder path
			fullpath = fullpath.substr(0, fullpath.length() - (strlen(moduleName) + 1));
			TTFoundationBinaryPath = fullpath;
			lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}
	}

#else // Some other platform, like Linux
    TTFoundationLoadExternalClassesFromFolder("/usr/local/lib/jamoma/extensions");
#endif
}

TTErr TTFoundationLoadExternalClassesFromFolder(const TTString& fullpath)
{
#if defined(TT_PLATFORM_MAC) || defined(TT_PLATFORM_LINUX) || defined(TT_PLATFORM_WIN)
 	TTExtensionInitializationMethod	initializer;
	TTString						initializerFunctionName;
	TTErr							err;
    TTPathVector					paths;
    TTPathIter						i;

#ifdef TT_PLATFORM_WIN
	TTString		windowsPathSpec = fullpath;
					windowsPathSpec += "/*.ttdll";
	WIN32_FIND_DATA	FindFileData;
	HANDLE			hFind = FindFirstFile(windowsPathSpec.c_str(), &FindFileData);

	if (hFind == INVALID_HANDLE_VALUE)
		return kTTErrGeneric;

    do {
    	printf("%s\n", FindFileData.cFileName);

		TTString	fileName(FindFileData.cFileName);
		TTString	fileSuffix(strrchr(fileName.c_str(), '.'));
		TTString	fileBaseName = fileName.substr(0, fileName.size() - 8);
		TTString	fileFullpath(fullpath);
		void*		handle = NULL;

		fileFullpath += "/";
		fileFullpath += fileName;
		std::cout << "EXTENSION: " << fileFullpath << std::endl;

//		handle = LoadLibrary(fileFullpath.c_str());
		handle = LoadLibrary(FindFileData.cFileName);
		std::cout << "HANDLE: " << handle << std::endl;
		if (!handle)
			continue;

		// TODO: assert -- or at least do a log post -- if handle is NULL
		initializerFunctionName = "TTLoadJamomaExtension_";
		initializerFunctionName += fileBaseName;
		initializer = (TTExtensionInitializationMethod)GetProcAddress((HMODULE)handle, initializerFunctionName.c_str());
		if (initializer)
			err = initializer();
		std::cout<< "Initializer: " << initializer << std::endl;

    } while (FindNextFile(hFind, &FindFileData));

    FindClose(hFind);

#else // good platforms

	DIR* dirp = opendir(fullpath.c_str());
	dirent* dp;
	while ((dp = readdir(dirp))) {
		TTString	fileName(dp->d_name);
		char*		cFileSuffix = strrchr(fileName.c_str(), '.');
		if (!cFileSuffix)
			continue;
		TTString	fileSuffix(cFileSuffix);
		TTString	fileBaseName = fileName.substr(0, fileName.size() - 8);
		TTString	fileFullpath(fullpath);
		void*		handle = NULL;

		fileFullpath += "/";
		fileFullpath += fileName;
		std::cout << "EXTENSION: " << fileFullpath << std::endl;

		// make sure the files have the correct extension before trying to load them
#ifdef TT_PLATFORM_LINUX
		if (fileSuffix != ".ttso")
#elif defined(TT_PLATFORM_MAC)
		if (fileSuffix != ".ttdylib")
#elif defined(TT_PLATFORM_WIN)
		if (fileSuffix != ".ttdll")
#endif
			continue;

#ifdef TT_PLATFORM_WIN
		handle = LoadLibrary(fileFullpath.c_str());
#else
		handle = dlopen(fileFullpath.c_str(), RTLD_LAZY);
#endif
		std::cout << "HANDLE: " << handle << std::endl;
		if (!handle)
			continue;

		// TODO: assert -- or at least do a log post -- if handle is NULL
		initializerFunctionName = "TTLoadJamomaExtension_";
		initializerFunctionName += fileBaseName;
#ifdef TT_PLATFORM_WIN
		initializer = (TTExtensionInitializationMethod)GetProcAddress((HMODULE)handle, initializerFunctionName.c_str());
#else
		initializer = (TTExtensionInitializationMethod)dlsym(handle, initializerFunctionName.c_str());
#endif
		if (initializer)
			err = initializer();

		std::cout<< "Initializer: " << initializer << std::endl;

	}
	closedir(dirp);

#endif // not windows
#endif // No dynamic loading on iOS
	return kTTErrNone;
}

<commit_msg>extension loading: cleaning up debug posts to console<commit_after>/*
 * Jamoma Foundation
 * Copyright © 2008, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTFoundation.h"
#include "TTSymbolTable.h"
#include "TTEnvironment.h"
#include "TTSymbolCache.h"
#include "TTCallback.h"

// Nodelib currently requires Boost Regex, which we don't have on the iOS
#ifndef DISABLE_NODELIB
#include "TTNodeLib.h"
#include "TTPath.h"
#endif

// Unit Tests
#include "TTMatrix.h"
#include "TTMatrixArray.h"
#include "TTInterpolate.test.h"
#include "TTString.test.h"
#include "TTSymbol.test.h"
#include "TTValue.test.h"
#include "TTDictionary.test.h"
// Nodelib currently requires Boost Regex, which we don't have on the iOS
#ifndef DISABLE_NODELIB
#include "TTNodeLib.test.h"
#endif

#ifdef TT_PLATFORM_MAC
#include <dlfcn.h>
#include <sys/types.h>
#include <dirent.h>
#elif TT_PLATFORM_LINUX
#include <dlfcn.h>
#elif TT_PLATFORM_WIN
#include <ShlObj.h>
#endif

#ifdef TT_PLATFORM_MAC
//#include <Carbon/Carbon.h>
#define __COREFOUNDATION_CFMESSAGEPORT__ 1
#include <CoreFoundation/CFBundle.h>
#endif

TTString        TTFoundationBinaryPath = "";

static bool		TTFoundationHasInitialized = false;

void            TTFoundationLoadExternalClasses(void);
TTErr           TTFoundationLoadExternalClassesFromFolder(const TTString& fullpath);
TTObjectBasePtr	TTFoundationInstantiateInternalClass(TTSymbol& className, TTValue& arguments);

/****************************************************************************************************/
void TTFoundationInit(const char* pathToBinaries)
{
	if (!TTFoundationHasInitialized) {
		TTFoundationHasInitialized = true;

		if (pathToBinaries)
			TTFoundationBinaryPath = pathToBinaries;

		for (int i=0; i<kNumTTDataTypes; i++)
			TTDataInfo::addDataInfoForType(TTDataType(i));

// Regex requires Boost libraries, not available for iOS for the time-being
#ifndef DISABLE_NODELIB
		TTNodeLibInit();
#endif

		ttEnvironment = new TTEnvironment;

// Regex requires Boost libraries, not available for iOS for the time-being
//#ifndef DISABLE_NODELIB
//		TTAddressCacheInit();
//#endif

#ifdef TT_DEBUG
		TTLogMessage("JamomaFoundation (TT_DEBUG) -- Version %s", TTFOUNDATION_VERSION_STRING);
		ttEnvironment->mDebugBasic = true;
#else
		TTLogMessage("JamomaFoundation -- Version %s", TTFOUNDATION_VERSION_STRING);
#endif
		if (pathToBinaries)
			TTLogMessage("-- Path %s\n", pathToBinaries);
		else
			TTLogMessage("\n");

		// register classes -- both internal and external
		TTCallback::registerClass();
		TTMatrix::registerClass();
		TTMatrixArray::registerClass();
		TTStringTest::registerClass();
		TTSymbolTest::registerClass();
		TTValueTest::registerClass();
		TTInterpolateTest::registerClass();
        TTDictionaryTest::registerClass();
// Regex requires Boost libraries, not available for iOS for the time-being
#ifndef DISABLE_NODELIB
		TTNodeLibTest::registerClass();
#endif

		TTFoundationLoadExternalClasses();
	}
}

void TTFoundationShutdown();
void TTFoundationShutdown()
{
	// FIXME: How do we call this (i.e. TTDSPShutdown()?) -- do we need to setup an observer of some sort on the environment class?
	// TODO: we need to free singletons like the environment here!
}

/****************************************************************************************************/

void TTFoundationLoadExternalClasses(void)
{
#ifdef TT_PLATFORM_MAC
	if (!TTFoundationBinaryPath.empty()) {
		// Look in the specified folder rather than the default location
		TTString extensionsPath = TTFoundationBinaryPath;
		extensionsPath += "/Extensions";
		TTFoundationLoadExternalClassesFromFolder(extensionsPath);
	}
	else {
		OSErr		err = noErr;
		TTString	fullpath;

#define LOOK_FOR_EXTENSIONS_IN_SAME_FOLDER_AS_LIB
#ifdef LOOK_FOR_EXTENSIONS_IN_SAME_FOLDER_AS_LIB
		Dl_info		info;
		char		mainBundleStr[4096];

		if (dladdr((const void*)TTFoundationLoadExternalClasses, &info)) {
			char *c = 0;

			printf("Loaded from path = %s\n", info.dli_fname);
			strncpy(mainBundleStr, info.dli_fname, 4096);
			c = strrchr(mainBundleStr, '/');
			if (c)
				*c = 0; // chop the "/JamomaFoundation.dylib off of the path

            // store binary path
            TTFoundationBinaryPath = mainBundleStr;
		}
#else // THE OLD WAY
		// Look in the folder of the host application
		CFBundleRef mainBundle = CFBundleGetMainBundle();
		CFURLRef	mainBundleURL = CFBundleCopyBundleURL(mainBundle);
		CFStringRef mainBundlePath = CFURLCopyFileSystemPath(mainBundleURL, kCFURLPOSIXPathStyle);
		char		mainBundleStr[4096];

		CFStringGetCString(mainBundlePath, mainBundleStr, 4096, kCFStringEncodingUTF8);
		strncat(mainBundleStr, "/Contents/Jamoma/Extensions", 4096);
		mainBundleStr[4095] = 0;

		CFRelease(mainBundlePath);
#endif

		err = TTFoundationLoadExternalClassesFromFolder(mainBundleStr);
		if (!err)
			return; // if we loaded classes out of a standalone app, then we don't want to be corrupted by global extensions Redmine #348
					// it could be that you want to create a standalone with a plug-in architecture -- for now that problem is ignored.

#ifdef OLD_MAC_EXTENSIONS_PATH
		// Look in ~/Library/Application Support/Jamoma/Extensions
		err = FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
		if (!err) {
			FSRefMakePath(&ref, path, 4096);
			fullpath = (char*)path;
			fullpath += "/Jamoma/Extensions";
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}

		// Look in /Library/Application Support/Jamoma/Extensions
		err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
		if (!err) {
			FSRefMakePath(&ref, path, 4096);
			fullpath = (char*)path;
			fullpath += "/Jamoma/Extensions";
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}
#else // NEW_MAC_EXTENSIONS_PATH
	    TTFoundationLoadExternalClassesFromFolder("/usr/local/jamoma/extensions");
#endif

	}
#elif TT_PLATFORM_WIN
	TTString	fullpath;
	char		temppath[4096];
	HKEY		hKey = 0;
	LONG		lRes;
	DWORD		dwSize = sizeof(temppath);
	HRESULT		hr;
	HINSTANCE	hInstance = GetModuleHandle(NULL);

	// Look in C:\Program Files\Common Files\TTBlue\Extensions
	//hr = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, SHGFP_TYPE_CURRENT, (LPSTR)temppath);

	//if (!FAILED(hr)) {
	//	fullpath = temppath;
	//	fullpath += "\\Jamoma\\Extensions\\";
	//	lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
	//	TTFoundationLoadExternalClassesFromFolder(fullpath);
	//}

	//// TODO: Look in some user-level directory like we do on the Mac?
	//
	//// Look in the support folder of the host application
	//if (hInstance) {
	//	GetModuleFileName(hInstance, (LPSTR)temppath, 4096);
	//	if (temppath[0]) {
	//		char *s = strrchr(temppath, '\\');
	//		if (s)
	//			*s = 0;
	//		fullpath = temppath;
	//		fullpath += "\\Jamoma\\Extensions\\";
	//		lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
	//		TTFoundationLoadExternalClassesFromFolder(fullpath);
	//	}
	//}

	// get the handle on JamomaFoundation.dll
	LPCSTR moduleName = "JamomaFoundation.dll";
	HMODULE	hmodule = GetModuleHandle(moduleName);
	// get the path
	GetModuleFileName(hmodule, (LPSTR)temppath, 4096);

	if (!FAILED(hmodule)) {
		if (temppath[0]) {
			fullpath = temppath;
			// get support folder path
			fullpath = fullpath.substr(0, fullpath.length() - (strlen(moduleName) + 1));
			TTFoundationBinaryPath = fullpath;
			lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}
	}

#else // Some other platform, like Linux
    TTFoundationLoadExternalClassesFromFolder("/usr/local/lib/jamoma/extensions");
#endif
}

TTErr TTFoundationLoadExternalClassesFromFolder(const TTString& fullpath)
{
#if defined(TT_PLATFORM_MAC) || defined(TT_PLATFORM_LINUX) || defined(TT_PLATFORM_WIN)
 	TTExtensionInitializationMethod	initializer;
	TTString						initializerFunctionName;
	TTErr							err;
    TTPathVector					paths;
    TTPathIter						i;

#ifdef TT_PLATFORM_WIN
	TTString		windowsPathSpec = fullpath;
					windowsPathSpec += "/*.ttdll";
	WIN32_FIND_DATA	FindFileData;
	HANDLE			hFind = FindFirstFile(windowsPathSpec.c_str(), &FindFileData);

	if (hFind == INVALID_HANDLE_VALUE)
		return kTTErrGeneric;

    do {
    	printf("%s\n", FindFileData.cFileName);

		TTString	fileName(FindFileData.cFileName);
		TTString	fileSuffix(strrchr(fileName.c_str(), '.'));
		TTString	fileBaseName = fileName.substr(0, fileName.size() - 8);
		TTString	fileFullpath(fullpath);
		void*		handle = NULL;

		fileFullpath += "/";
		fileFullpath += fileName;
		//std::cout << "EXTENSION: " << fileFullpath << std::endl;

		handle = LoadLibrary(FindFileData.cFileName);
		//std::cout << "HANDLE: " << handle << std::endl;
		if (!handle)
			continue;

		// TODO: assert -- or at least do a log post -- if handle is NULL
		initializerFunctionName = "TTLoadJamomaExtension_";
		initializerFunctionName += fileBaseName;
		initializer = (TTExtensionInitializationMethod)GetProcAddress((HMODULE)handle, initializerFunctionName.c_str());
		if (initializer)
			err = initializer();
		//std::cout<< "Initializer: " << initializer << std::endl;

    } while (FindNextFile(hFind, &FindFileData));

    FindClose(hFind);

#else // good platforms

	DIR* dirp = opendir(fullpath.c_str());
	dirent* dp;
	while ((dp = readdir(dirp))) {
		TTString	fileName(dp->d_name);
		char*		cFileSuffix = strrchr(fileName.c_str(), '.');
		if (!cFileSuffix)
			continue;
		TTString	fileSuffix(cFileSuffix);
		TTString	fileBaseName = fileName.substr(0, fileName.size() - 8);
		TTString	fileFullpath(fullpath);
		void*		handle = NULL;

		fileFullpath += "/";
		fileFullpath += fileName;
		std::cout << "EXTENSION: " << fileFullpath << std::endl;

		// make sure the files have the correct extension before trying to load them
#ifdef TT_PLATFORM_LINUX
		if (fileSuffix != ".ttso")
#elif defined(TT_PLATFORM_MAC)
		if (fileSuffix != ".ttdylib")
#elif defined(TT_PLATFORM_WIN)
		if (fileSuffix != ".ttdll")
#endif
			continue;

#ifdef TT_PLATFORM_WIN
		handle = LoadLibrary(fileFullpath.c_str());
#else
		handle = dlopen(fileFullpath.c_str(), RTLD_LAZY);
#endif
		//std::cout << "HANDLE: " << handle << std::endl;
		if (!handle)
			continue;

		// TODO: assert -- or at least do a log post -- if handle is NULL
		initializerFunctionName = "TTLoadJamomaExtension_";
		initializerFunctionName += fileBaseName;
#ifdef TT_PLATFORM_WIN
		initializer = (TTExtensionInitializationMethod)GetProcAddress((HMODULE)handle, initializerFunctionName.c_str());
#else
		initializer = (TTExtensionInitializationMethod)dlsym(handle, initializerFunctionName.c_str());
#endif
		if (initializer)
			err = initializer();

		//std::cout<< "Initializer: " << initializer << std::endl;

	}
	closedir(dirp);

#endif // not windows
#endif // No dynamic loading on iOS
	return kTTErrNone;
}

<|endoftext|>


<commit_before>/* Copyright 2015 Samsung Electronics Co., LTD
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "activity_jni.h"
#include <jni.h>
#include <glm/gtc/type_ptr.hpp>
#include "VrApi_Helpers.h"

static const char * activityClassName = "org/gearvrf/GVRActivity";

namespace gvr {

extern "C"
{

long Java_org_gearvrf_GVRActivity_nativeSetAppInterface(
        JNIEnv * jni, jclass clazz, jobject activity,
        jstring fromPackageName, jstring commandString,
        jstring uriString)
{
    LOG("GVRActivity::nativeSetupAppInterface ");
    return (new GVRActivity(*jni,activity))->SetActivity( jni, clazz, activity, fromPackageName, commandString, uriString );
}

void Java_org_gearvrf_GVRActivity_nativeSetCamera(
        JNIEnv * jni, jclass clazz, jlong appPtr, jlong jcamera )
{
    GVRActivity *activity = (GVRActivity*)((OVR::App *)appPtr)->GetAppInterface();
    Camera* camera = reinterpret_cast<Camera*>(jcamera);
    activity->camera = camera;
}

} // extern "C"

//=============================================================================
//                             GVRActivity
//=============================================================================

GVRActivity::GVRActivity(JNIEnv & jni_, jobject activityObject_)
    : forceScreenClear( false )
    , ModelLoaded( false )
    , UiJni(&jni_)
    , viewManager(NULL)
{
    viewManager = new GVRViewManager(jni_,activityObject_);
    javaObject = UiJni->NewGlobalRef( activityObject_ );
    activityClass = GetGlobalClassReference( activityClassName );

    oneTimeInitMethodId     = GetMethodID( "oneTimeInit", "()V" );
    oneTimeShutdownMethodId = GetMethodID( "oneTimeShutDown", "()V" );

    drawFrameMethodId      = GetMethodID( "drawFrame", "()V" );
    beforeDrawEyesMethodId = GetMethodID( "beforeDrawEyes", "()V" );
    drawEyeViewMethodId = GetMethodID( "onDrawEyeView", "(IF)V" );
    afterDrawEyesMethodId = GetMethodID( "afterDrawEyes", "()V" );

    onKeyEventNativeMethodId = GetMethodID("onKeyEventNative", "(II)Z");
}

GVRActivity::~GVRActivity() {
    LOG( "GVRActivity::~GVRActivity()");
    if ( javaObject != 0 )
    {
        UiJni->DeleteGlobalRef( javaObject );
    }
}

jmethodID GVRActivity::GetStaticMethodID( jclass clazz, const char * name, const char * signature )
{
    jmethodID mid = UiJni->GetStaticMethodID( clazz, name, signature );
    if ( !mid )
    {
        FAIL( "couldn't get %s", name );
    }
    return mid;
}

jmethodID GVRActivity::GetMethodID( const char * name, const char * signature )
{
    jmethodID mid = UiJni->GetMethodID( activityClass, name, signature );
    if ( !mid )
    {
        FAIL( "couldn't get %s", name );
    }
    return mid;
}

jclass GVRActivity::GetGlobalClassReference( const char * className ) const
{
    jclass lc = UiJni->FindClass(className);
    if ( lc == 0 )
    {
        FAIL( "FindClass( %s ) failed", className );
    }
    // Turn it into a global ref, so we can safely use it in the VR thread
    jclass gc = (jclass)UiJni->NewGlobalRef( lc );

    UiJni->DeleteLocalRef( lc );

    return gc;
}

void GVRActivity::Configure( OVR::ovrSettings & settings )
{
    LOG( "GVRActivity::Configure");
    settings.EyeBufferParms.multisamples = 2;
    // leave the rest as default for now.
    // TODO: take values specified in xml and set them here.
}

void GVRActivity::OneTimeInit( const char * fromPackage, const char * launchIntentJSON, const char * launchIntentURI )
{
    LOG( "GVRActivity::OneTimeInit" );
    app->GetVrJni()->CallVoidMethod( javaObject, oneTimeInitMethodId );

    // Check if we already loaded the model through an intent
    if ( !ModelLoaded )
    {
        InitSceneObject();
    }
}

void GVRActivity::OneTimeShutdown()
{
    LOG( "GVRActivity::OneTimeShutdown" );

    app->GetVrJni()->CallVoidMethod( javaObject, oneTimeShutdownMethodId );

    // Free GL resources
}

void GVRActivity::NewIntent( const char * fromPackageName, const char * command, const char * uri )
{
	InitSceneObject();
}

void GVRActivity::Command( const char * msg )
{
    //LOG( "GVRActivity::Command %s", msg );
}

void GVRActivity::WindowCreated(){
    //LOG( "GVRActivity::WindowCreated");
}

OVR::Matrix4f GVRActivity::GetEyeView( const int eye, const float fovDegrees ) const
{
    const OVR::Matrix4f projectionMatrix = Scene.ProjectionMatrixForEye( eye, fovDegrees );
    const OVR::Matrix4f viewMatrix = Scene.ViewMatrixForEye( eye );
    return ( projectionMatrix * viewMatrix );

}

OVR::Matrix4f GVRActivity::DrawEyeView( const int eye, const float fovDegrees )
{
    const OVR::Matrix4f view = GetEyeView( eye, fovDegrees );

	// Transpose view matrix from oculus to mvp_matrix to rendering correctly with gvrf renderer.
    mvp_matrix = glm::mat4(
            view.M[0][0], view.M[1][0], view.M[2][0], view.M[3][0],
            view.M[0][1], view.M[1][1], view.M[2][1], view.M[3][1],
            view.M[0][2], view.M[1][2], view.M[2][2], view.M[3][2],
            view.M[0][3], view.M[1][3], view.M[2][3], view.M[3][3]);

    SetMVPMatrix(mvp_matrix);

    JNIEnv* jni = app->GetVrJni();
    jni->CallVoidMethod( javaObject, drawEyeViewMethodId, eye, fovDegrees );

    if(eye == 1) {
        jni->CallVoidMethod( javaObject, afterDrawEyesMethodId );
    }

    glm::mat4 view_matrix = camera->getViewMatrix();
    glm::mat4 projection_matrix = camera->getProjectionMatrix(); //gun
    glm::mat4 vp_matrix = glm::mat4(projection_matrix * view_matrix);

    OVR::Matrix4f view2 = OVR::Matrix4f(
    		vp_matrix[0][0], vp_matrix[1][0], vp_matrix[2][0], vp_matrix[3][0],
            vp_matrix[0][1], vp_matrix[1][1], vp_matrix[2][1], vp_matrix[3][1],
            vp_matrix[0][2], vp_matrix[1][2], vp_matrix[2][2], vp_matrix[3][2],
            vp_matrix[0][3], vp_matrix[1][3], vp_matrix[2][3], vp_matrix[3][3]);

    return view2;

}

OVR::Matrix4f GVRActivity::Frame( const OVR::VrFrame & vrFrame )
{
    LOGD("GVRActivity::Frame() was called");

    JNIEnv* jni = app->GetVrJni();
    jni->CallVoidMethod( javaObject, beforeDrawEyesMethodId );
    jni->CallVoidMethod( javaObject, drawFrameMethodId );

	//This is called once while DrawEyeView is called twice, when eye=0 and eye 1.
	//So camera is set in java as one of left and right camera.
	//Centerview camera matrix can be retrieved from its parent, CameraRig
    glm::mat4 vp_matrix = camera->getCenterViewMatrix();

    ovrMatrix4f view2;

    view2.M[0][0] = vp_matrix[0][0]; view2.M[1][0] = vp_matrix[0][1]; view2.M[2][0] = vp_matrix[0][2]; view2.M[3][0] = vp_matrix[0][3];
    view2.M[0][1] = vp_matrix[1][0]; view2.M[1][1] = vp_matrix[1][1]; view2.M[2][1] = vp_matrix[1][2]; view2.M[3][1] = vp_matrix[1][3];
    view2.M[0][2] = vp_matrix[2][0]; view2.M[1][2] = vp_matrix[2][1]; view2.M[2][2] = vp_matrix[2][2]; view2.M[3][2] = vp_matrix[2][3];
    view2.M[0][3] = vp_matrix[3][0]; view2.M[1][3] = vp_matrix[3][1]; view2.M[2][3] = vp_matrix[3][2]; view2.M[3][3] = vp_matrix[3][3];

    return view2;
}

void GVRActivity::InitSceneObject()
{
}

bool GVRActivity::OnKeyEvent(const int keyCode, const int repeatCode,
        const OVR::KeyEventType eventType) {

    // 1: KeyState::KEY_EVENT_DOWN, 0: KeyState::KEY_EVENT_UP. Other information is lost from Oculus side.
    int isDown = (eventType == OVR::KEY_EVENT_DOWN) ? 1 : 0;

    return app->GetVrJni()->CallBooleanMethod(javaObject,
            onKeyEventNativeMethodId, keyCode, isDown);
}

}
<commit_msg>Removing per-frame log spew.<commit_after>/* Copyright 2015 Samsung Electronics Co., LTD
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "activity_jni.h"
#include <jni.h>
#include <glm/gtc/type_ptr.hpp>
#include "VrApi_Helpers.h"

static const char * activityClassName = "org/gearvrf/GVRActivity";

namespace gvr {

extern "C"
{

long Java_org_gearvrf_GVRActivity_nativeSetAppInterface(
        JNIEnv * jni, jclass clazz, jobject activity,
        jstring fromPackageName, jstring commandString,
        jstring uriString)
{
    return (new GVRActivity(*jni,activity))->SetActivity( jni, clazz, activity, fromPackageName, commandString, uriString );
}

void Java_org_gearvrf_GVRActivity_nativeSetCamera(
        JNIEnv * jni, jclass clazz, jlong appPtr, jlong jcamera )
{
    GVRActivity *activity = (GVRActivity*)((OVR::App *)appPtr)->GetAppInterface();
    Camera* camera = reinterpret_cast<Camera*>(jcamera);
    activity->camera = camera;
}

} // extern "C"

//=============================================================================
//                             GVRActivity
//=============================================================================

GVRActivity::GVRActivity(JNIEnv & jni_, jobject activityObject_)
    : forceScreenClear( false )
    , ModelLoaded( false )
    , UiJni(&jni_)
    , viewManager(NULL)
{
    viewManager = new GVRViewManager(jni_,activityObject_);
    javaObject = UiJni->NewGlobalRef( activityObject_ );
    activityClass = GetGlobalClassReference( activityClassName );

    oneTimeInitMethodId     = GetMethodID( "oneTimeInit", "()V" );
    oneTimeShutdownMethodId = GetMethodID( "oneTimeShutDown", "()V" );

    drawFrameMethodId      = GetMethodID( "drawFrame", "()V" );
    beforeDrawEyesMethodId = GetMethodID( "beforeDrawEyes", "()V" );
    drawEyeViewMethodId = GetMethodID( "onDrawEyeView", "(IF)V" );
    afterDrawEyesMethodId = GetMethodID( "afterDrawEyes", "()V" );

    onKeyEventNativeMethodId = GetMethodID("onKeyEventNative", "(II)Z");
}

GVRActivity::~GVRActivity() {
    if ( javaObject != 0 )
    {
        UiJni->DeleteGlobalRef( javaObject );
    }
}

jmethodID GVRActivity::GetStaticMethodID( jclass clazz, const char * name, const char * signature )
{
    jmethodID mid = UiJni->GetStaticMethodID( clazz, name, signature );
    if ( !mid )
    {
        FAIL( "couldn't get %s", name );
    }
    return mid;
}

jmethodID GVRActivity::GetMethodID( const char * name, const char * signature )
{
    jmethodID mid = UiJni->GetMethodID( activityClass, name, signature );
    if ( !mid )
    {
        FAIL( "couldn't get %s", name );
    }
    return mid;
}

jclass GVRActivity::GetGlobalClassReference( const char * className ) const
{
    jclass lc = UiJni->FindClass(className);
    if ( lc == 0 )
    {
        FAIL( "FindClass( %s ) failed", className );
    }
    // Turn it into a global ref, so we can safely use it in the VR thread
    jclass gc = (jclass)UiJni->NewGlobalRef( lc );

    UiJni->DeleteLocalRef( lc );

    return gc;
}

void GVRActivity::Configure( OVR::ovrSettings & settings )
{
    settings.EyeBufferParms.multisamples = 2;
    // leave the rest as default for now.
    // TODO: take values specified in xml and set them here.
}

void GVRActivity::OneTimeInit( const char * fromPackage, const char * launchIntentJSON, const char * launchIntentURI )
{
    app->GetVrJni()->CallVoidMethod( javaObject, oneTimeInitMethodId );

    // Check if we already loaded the model through an intent
    if ( !ModelLoaded )
    {
        InitSceneObject();
    }
}

void GVRActivity::OneTimeShutdown()
{

    app->GetVrJni()->CallVoidMethod( javaObject, oneTimeShutdownMethodId );

    // Free GL resources
}

void GVRActivity::NewIntent( const char * fromPackageName, const char * command, const char * uri )
{
	InitSceneObject();
}

void GVRActivity::Command( const char * msg )
{
    //LOG( "GVRActivity::Command %s", msg );
}

void GVRActivity::WindowCreated(){
    //LOG( "GVRActivity::WindowCreated");
}

OVR::Matrix4f GVRActivity::GetEyeView( const int eye, const float fovDegrees ) const
{
    const OVR::Matrix4f projectionMatrix = Scene.ProjectionMatrixForEye( eye, fovDegrees );
    const OVR::Matrix4f viewMatrix = Scene.ViewMatrixForEye( eye );
    return ( projectionMatrix * viewMatrix );

}

OVR::Matrix4f GVRActivity::DrawEyeView( const int eye, const float fovDegrees )
{
    const OVR::Matrix4f view = GetEyeView( eye, fovDegrees );

	// Transpose view matrix from oculus to mvp_matrix to rendering correctly with gvrf renderer.
    mvp_matrix = glm::mat4(
            view.M[0][0], view.M[1][0], view.M[2][0], view.M[3][0],
            view.M[0][1], view.M[1][1], view.M[2][1], view.M[3][1],
            view.M[0][2], view.M[1][2], view.M[2][2], view.M[3][2],
            view.M[0][3], view.M[1][3], view.M[2][3], view.M[3][3]);

    SetMVPMatrix(mvp_matrix);

    JNIEnv* jni = app->GetVrJni();
    jni->CallVoidMethod( javaObject, drawEyeViewMethodId, eye, fovDegrees );

    if(eye == 1) {
        jni->CallVoidMethod( javaObject, afterDrawEyesMethodId );
    }

    glm::mat4 view_matrix = camera->getViewMatrix();
    glm::mat4 projection_matrix = camera->getProjectionMatrix(); //gun
    glm::mat4 vp_matrix = glm::mat4(projection_matrix * view_matrix);

    OVR::Matrix4f view2 = OVR::Matrix4f(
    		vp_matrix[0][0], vp_matrix[1][0], vp_matrix[2][0], vp_matrix[3][0],
            vp_matrix[0][1], vp_matrix[1][1], vp_matrix[2][1], vp_matrix[3][1],
            vp_matrix[0][2], vp_matrix[1][2], vp_matrix[2][2], vp_matrix[3][2],
            vp_matrix[0][3], vp_matrix[1][3], vp_matrix[2][3], vp_matrix[3][3]);

    return view2;

}

OVR::Matrix4f GVRActivity::Frame( const OVR::VrFrame & vrFrame )
{
    JNIEnv* jni = app->GetVrJni();
    jni->CallVoidMethod( javaObject, beforeDrawEyesMethodId );
    jni->CallVoidMethod( javaObject, drawFrameMethodId );

	//This is called once while DrawEyeView is called twice, when eye=0 and eye 1.
	//So camera is set in java as one of left and right camera.
	//Centerview camera matrix can be retrieved from its parent, CameraRig
    glm::mat4 vp_matrix = camera->getCenterViewMatrix();

    ovrMatrix4f view2;

    view2.M[0][0] = vp_matrix[0][0]; view2.M[1][0] = vp_matrix[0][1]; view2.M[2][0] = vp_matrix[0][2]; view2.M[3][0] = vp_matrix[0][3];
    view2.M[0][1] = vp_matrix[1][0]; view2.M[1][1] = vp_matrix[1][1]; view2.M[2][1] = vp_matrix[1][2]; view2.M[3][1] = vp_matrix[1][3];
    view2.M[0][2] = vp_matrix[2][0]; view2.M[1][2] = vp_matrix[2][1]; view2.M[2][2] = vp_matrix[2][2]; view2.M[3][2] = vp_matrix[2][3];
    view2.M[0][3] = vp_matrix[3][0]; view2.M[1][3] = vp_matrix[3][1]; view2.M[2][3] = vp_matrix[3][2]; view2.M[3][3] = vp_matrix[3][3];

    return view2;
}

void GVRActivity::InitSceneObject()
{
}

bool GVRActivity::OnKeyEvent(const int keyCode, const int repeatCode,
        const OVR::KeyEventType eventType) {

    // 1: KeyState::KEY_EVENT_DOWN, 0: KeyState::KEY_EVENT_UP. Other information is lost from Oculus side.
    int isDown = (eventType == OVR::KEY_EVENT_DOWN) ? 1 : 0;

    return app->GetVrJni()->CallBooleanMethod(javaObject,
            onKeyEventNativeMethodId, keyCode, isDown);
}

}
<|endoftext|>


<commit_before>#include "microfacet.h"
#include "reflection.h"

//直接copy自PBRT的GGX粗糙度到alpha的工具函数
Float GGXRoughnessToAlpha(Float roughness) {
	roughness = std::max(roughness, (Float)1e-3);
	Float x = std::log(roughness);
	return 1.62142f + 0.819955f * x + 0.1734f * x * x + 0.0171201f * x * x * x +
		0.000640711f * x * x * x * x;
}

Float IsotropyBeckmannDistribution::D(const Vector3f &wh) const{
	//1.原始公式
	////计算tan(theta)^2
	//Float tanTheta2=TanTheta2(wh);
	////graze angle
	//if (std::isinf(tanTheta2)) {
	//	return 0;
	//}
	////代入公式
	//Float alpha2 = _alpha*_alpha;
	//Float cosTheta2 = CosTheta2(wh);
	//return std::exp(-tanTheta2 / alpha2) / (Pi*alpha2*cosTheta2*cosTheta2);

	//2.简化公式
	Float cosTheta2 = CosTheta2(wh);
	if (cosTheta2 == 0) {
		return 0;
	}
	Float alpha2 = _alpha*_alpha;
	return std::exp((cosTheta2 - 1) / (alpha2*cosTheta2)) / (Pi*alpha2*cosTheta2*cosTheta2);
}

Float IsotropyBeckmannDistribution::Lambda(const Vector3f &w) const{
	//这种东西真的是要靠科学家来推导出来，厉害厉害
    Float absTanTheta=std::abs(TanTheta(w));
    if(std::isinf(absTanTheta)){
        return 0;
    }
    Float a=1/(_alpha*absTanTheta);
    if(a>1.6){
        return 0;
    }
    else{
        return (1-1.259*a+0.396*a*a)/(3.535*a+2.181*a*a);
    }
}

Vector3f IsotropyBeckmannDistribution::Sample_wh(const Vector3f &wo, const Point2f &u) const {

	Float logSample=std::log(u[0]);
	if (std::isinf(logSample)) {
		logSample = 0;
	}
	Float tanTheta2 = -(_alpha*_alpha)*logSample;
	Float cosTheta = 1 / (std::sqrt(tanTheta2 + 1));
	Float sinTheta = std::sqrt(std::max((Float)0.0, 1 - cosTheta*cosTheta));

    Float phi=2*Pi*u[1];
	Vector3f wh= SphericalDirection(sinTheta,cosTheta,phi);
	//保证在同一个半球
	if (!SameHemisphere(wo, wh)) {
		wh = -wh;
	}
    return wh;
}

Float AnisotropyGGXDistribution::D(const Vector3f &wh) const {

    Float cosTheta=AbsCosTheta(wh);
    if(cosTheta==0){
        return 0;
    }
    Float cosTheta4=(cosTheta*cosTheta)*(cosTheta*cosTheta);
    Float tanTheta2=TanTheta2(wh);

    Float sinPhi2=SinPhi2(wh);
    Float cosPhi2=CosPhi2(wh);

    Float alphaX2=_alphaX*_alphaX;
    Float alphaY2=_alphaY*_alphaY;

    Float term1=1+(cosPhi2/alphaX2+sinPhi2/alphaY2)*tanTheta2;
    Float term2=term1*term1;
    return 1.0/(Pi*_alphaX*_alphaY*cosTheta4*term2);
}

Float AnisotropyGGXDistribution::Lambda(const Vector3f &w) const{
    Float tanTheta2=TanTheta2(w);
    if(std::isinf(tanTheta2)){
        return 0;
    }
    Float alpha = std::sqrt(CosPhi2(w) * _alphaX * _alphaX +SinPhi2(w) * _alphaY * _alphaY);

    return (-1.0+std::sqrt(1.0+alpha*alpha*tanTheta2))/2.0;
}

Float IsotropyGGXDistribution::D(const Vector3f &wh) const {
	//各向同性版本和各向异性版本是有区别的
	//気をつけて
	Float cosTheta = AbsCosTheta(wh);
	if (cosTheta == 0) {
		return 0;
	}

	//这里使用简化成只包含一个cos(theta)成分的公式 GGX=a^2/[PI*(cos(theta)^2x(a^2-1)+1)^2]
	Float alpha2 = _alpha*_alpha;
	Float cosTheta2 = cosTheta*cosTheta;
	Float term = cosTheta2*(alpha2 - 1) + 1;
	return alpha2 / (Pi*term*term);
}

Float IsotropyGGXDistribution::Lambda(const Vector3f &w) const {
	//各向同性版本和各向异性版本是有区别的
	//気をつけて
	Float tanTheta2 = TanTheta2(w);
	if (std::isinf(tanTheta2)) {
		return 0;
	}

	return (-1.0 + std::sqrt(1.0 + _alpha*_alpha*tanTheta2))/2.0;
}

//这个是各项同性版本
 Vector3f IsotropyGGXDistribution::Sample_wh(const Vector3f &wo, const Point2f &u) const{
     //Pdf(theta)和Pdf(phi)是两个独立分布，因此可以独立处理
     Float phi=u.x*2*Pi;
     Float cosTheta=0;

	 cosTheta=std::sqrt((1-u.y)/(1+u.y*(_alpha*_alpha-1)));
     //sin2+cos2=1
     Float sinTheta=std::max(0.0,std::sqrt(1.0-(cosTheta*cosTheta)));
     Float x=sinTheta*std::cos(phi);
     Float y=sinTheta*std::sin(phi);
     Float z=cosTheta;
     Vector3f wh=Vector3f(x,y,z);
     //到底需不需要让wo和wh在同一个半球内，我并没有完全理解，暂时注释掉
	 //这里貌似应该要让wo和wh保持在同一个半球内,对D和pdf函数都没有影响
	 if(CosTheta(wo)<0){
         wh=-wh;
     }
     return wh;
 }

 //这个是各项同性版本
 //PDF = D * COS(wh)
 //返回的是半角向量空间的
 Float MicrofacetDistribution::Pdf(const Vector3f &wo, const Vector3f &wh) const {
	 return D(wh)*AbsCosTheta(wh);
 }<commit_msg>多添加了一个注释<commit_after>#include "microfacet.h"
#include "reflection.h"

//直接copy自PBRT的GGX粗糙度到alpha的工具函数
Float GGXRoughnessToAlpha(Float roughness) {
	roughness = std::max(roughness, (Float)1e-3);
	Float x = std::log(roughness);
	return 1.62142f + 0.819955f * x + 0.1734f * x * x + 0.0171201f * x * x * x +
		0.000640711f * x * x * x * x;
}

Float IsotropyBeckmannDistribution::D(const Vector3f &wh) const{
	//1.原始公式
	////计算tan(theta)^2
	//Float tanTheta2=TanTheta2(wh);
	////graze angle
	//if (std::isinf(tanTheta2)) {
	//	return 0;
	//}
	////代入公式
	//Float alpha2 = _alpha*_alpha;
	//Float cosTheta2 = CosTheta2(wh);
	//return std::exp(-tanTheta2 / alpha2) / (Pi*alpha2*cosTheta2*cosTheta2);

	//2.简化公式
	Float cosTheta2 = CosTheta2(wh);
	if (cosTheta2 == 0) {
		return 0;
	}
	Float alpha2 = _alpha*_alpha;
	return std::exp((cosTheta2 - 1) / (alpha2*cosTheta2)) / (Pi*alpha2*cosTheta2*cosTheta2);
}

Float IsotropyBeckmannDistribution::Lambda(const Vector3f &w) const{
	//这种东西真的是要靠科学家来推导出来，厉害厉害
    Float absTanTheta=std::abs(TanTheta(w));
    if(std::isinf(absTanTheta)){
        return 0;
    }
    Float a=1/(_alpha*absTanTheta);
    if(a>1.6){
        return 0;
    }
    else{
        return (1-1.259*a+0.396*a*a)/(3.535*a+2.181*a*a);
    }
}

Vector3f IsotropyBeckmannDistribution::Sample_wh(const Vector3f &wo, const Point2f &u) const {

	Float logSample=std::log(u[0]);
	if (std::isinf(logSample)) {
		logSample = 0;
	}
	Float tanTheta2 = -(_alpha*_alpha)*logSample;
	Float cosTheta = 1 / (std::sqrt(tanTheta2 + 1));
	Float sinTheta = std::sqrt(std::max((Float)0.0, 1 - cosTheta*cosTheta));

    Float phi=2*Pi*u[1];
	Vector3f wh= SphericalDirection(sinTheta,cosTheta,phi);
	//保证在同一个半球
	if (!SameHemisphere(wo, wh)) {
		wh = -wh;
	}
    return wh;
}

Float AnisotropyGGXDistribution::D(const Vector3f &wh) const {

    Float cosTheta=AbsCosTheta(wh);
    if(cosTheta==0){
        return 0;
    }
    Float cosTheta4=(cosTheta*cosTheta)*(cosTheta*cosTheta);
    Float tanTheta2=TanTheta2(wh);

    Float sinPhi2=SinPhi2(wh);
    Float cosPhi2=CosPhi2(wh);

    Float alphaX2=_alphaX*_alphaX;
    Float alphaY2=_alphaY*_alphaY;

    Float term1=1+(cosPhi2/alphaX2+sinPhi2/alphaY2)*tanTheta2;
    Float term2=term1*term1;
    return 1.0/(Pi*_alphaX*_alphaY*cosTheta4*term2);
}

Float AnisotropyGGXDistribution::Lambda(const Vector3f &w) const{
    Float tanTheta2=TanTheta2(w);
    if(std::isinf(tanTheta2)){
        return 0;
    }
    Float alpha = std::sqrt(CosPhi2(w) * _alphaX * _alphaX +SinPhi2(w) * _alphaY * _alphaY);

    return (-1.0+std::sqrt(1.0+alpha*alpha*tanTheta2))/2.0;
}

Float IsotropyGGXDistribution::D(const Vector3f &wh) const {
	//各向同性版本和各向异性版本是有区别的
	//気をつけて
	Float cosTheta = AbsCosTheta(wh);
	if (cosTheta == 0) {
		return 0;
	}

	//这里使用简化成只包含一个cos(theta)成分的公式 GGX=a^2/[PI*(cos(theta)^2x(a^2-1)+1)^2]
	Float alpha2 = _alpha*_alpha;
	Float cosTheta2 = cosTheta*cosTheta;
	Float term = cosTheta2*(alpha2 - 1) + 1;
	return alpha2 / (Pi*term*term);
}

Float IsotropyGGXDistribution::Lambda(const Vector3f &w) const {
	//各向同性版本和各向异性版本是有区别的
	//気をつけて
	Float tanTheta2 = TanTheta2(w);
	if (std::isinf(tanTheta2)) {
		return 0;
	}

	return (-1.0 + std::sqrt(1.0 + _alpha*_alpha*tanTheta2))/2.0;
}

//这个是各项同性版本
 Vector3f IsotropyGGXDistribution::Sample_wh(const Vector3f &wo, const Point2f &u) const{
     //Pdf(theta)和Pdf(phi)是两个独立分布，因此可以独立处理
     Float phi=u.x*2*Pi;
     Float cosTheta=0;

	 cosTheta=std::sqrt((1-u.y)/(1+u.y*(_alpha*_alpha-1)));
     //sin2+cos2=1
     Float sinTheta=std::max(0.0,std::sqrt(1.0-(cosTheta*cosTheta)));
     Float x=sinTheta*std::cos(phi);
     Float y=sinTheta*std::sin(phi);
     Float z=cosTheta;
     Vector3f wh=Vector3f(x,y,z);
     //到底需不需要让wo和wh在同一个半球内，我并没有完全理解，暂时注释掉
	 //这里貌似应该要让wo和wh保持在同一个半球内,对D和pdf函数都没有影响
	 if(CosTheta(wo)<0){
         wh=-wh;
     }
     return wh;
 }

 //这个是各项同性版本
 //PDF = D * COS(wh)
 //返回的是半角向量空间的
 Float MicrofacetDistribution::Pdf(const Vector3f &wo, const Vector3f &wh) const {
	 //其实这里就是可见法线分布函数,可以查阅Heiz的GREAT论文！
	 return D(wh)*AbsCosTheta(wh);
 }<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QMessageBox>
#include <QModelIndexList>
#include <QSpacerItem>
#include <QVBoxLayout>

#include <nitroshare/application.h>
#include <nitroshare/plugin.h>
#include <nitroshare/pluginmodel.h>

#include "plugindialog.h"

PluginDialog::PluginDialog(Application *application)
    : mApplication(application),
      mTableView(new QTableView),
      mLoadButton(new QPushButton(tr("Load"))),
      mUnloadButton(new QPushButton(tr("Unload")))
{
    setWindowTitle(tr("Plugins"));
    resize(800, 300);

    mModel.setSourceModel(application->pluginModel());

    mTableView->setModel(&mModel);
    mTableView->horizontalHeader()->setDefaultSectionSize(160);
    mTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    mTableView->horizontalHeader()->setStretchLastSection(true);
    mTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    mTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    mTableView->verticalHeader()->setVisible(false);

    connect(mTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PluginDialog::onSelectionChanged);

    mLoadButton->setEnabled(false);
    connect(mLoadButton, &QPushButton::clicked, this, &PluginDialog::onLoad);

    mUnloadButton->setEnabled(false);
    connect(mUnloadButton, &QPushButton::clicked, this, &PluginDialog::onUnload);

    QVBoxLayout *vboxLayout = new QVBoxLayout;
    vboxLayout->addWidget(mLoadButton);
    vboxLayout->addWidget(mUnloadButton);
    vboxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));

    QHBoxLayout *hboxLayout = new QHBoxLayout;
    hboxLayout->addWidget(mTableView);
    hboxLayout->addLayout(vboxLayout);
    setLayout(hboxLayout);
}

void PluginDialog::onSelectionChanged()
{
    Plugin *plugin = currentPlugin();

    mLoadButton->setEnabled(plugin && !plugin->isLoaded());
    mUnloadButton->setEnabled(plugin && plugin->isLoaded());
}

void PluginDialog::onLoad()
{
    mApplication->pluginModel()->load(currentPlugin());
    mTableView->selectionModel()->clear();
}

void PluginDialog::onUnload()
{
    Plugin *plugin = currentPlugin();
    if (plugin->name() == "pluginui") {
        int response = QMessageBox::warning(
            this,
            tr("Warning"),
            tr("Unloading the pluginui plugin will close this dialog and make further changes impossible. Are you sure you want to unload this plugin?"),
            QMessageBox::Yes | QMessageBox::No
        );
        if (response == QMessageBox::No) {
            return;
        }
    }
    mApplication->pluginModel()->unload(plugin);
    mTableView->selectionModel()->clear();
}

Plugin *PluginDialog::currentPlugin() const
{
    QModelIndexList selection(mTableView->selectionModel()->selectedIndexes());
    return selection.size() ? selection.at(0).data(Qt::UserRole).value<Plugin*>() : nullptr;
}
<commit_msg>Fix crash when unloading pluginui plugin.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QMessageBox>
#include <QModelIndexList>
#include <QSpacerItem>
#include <QVBoxLayout>

#include <nitroshare/application.h>
#include <nitroshare/plugin.h>
#include <nitroshare/pluginmodel.h>

#include "plugindialog.h"

const QString ThisPlugin = "pluginui";

PluginDialog::PluginDialog(Application *application)
    : mApplication(application),
      mTableView(new QTableView),
      mLoadButton(new QPushButton(tr("Load"))),
      mUnloadButton(new QPushButton(tr("Unload")))
{
    setWindowTitle(tr("Plugins"));
    resize(800, 300);

    mModel.setSourceModel(application->pluginModel());

    mTableView->setModel(&mModel);
    mTableView->horizontalHeader()->setDefaultSectionSize(160);
    mTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    mTableView->horizontalHeader()->setStretchLastSection(true);
    mTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    mTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    mTableView->verticalHeader()->setVisible(false);

    connect(mTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PluginDialog::onSelectionChanged);

    mLoadButton->setEnabled(false);
    connect(mLoadButton, &QPushButton::clicked, this, &PluginDialog::onLoad);

    mUnloadButton->setEnabled(false);
    connect(mUnloadButton, &QPushButton::clicked, this, &PluginDialog::onUnload);

    QVBoxLayout *vboxLayout = new QVBoxLayout;
    vboxLayout->addWidget(mLoadButton);
    vboxLayout->addWidget(mUnloadButton);
    vboxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));

    QHBoxLayout *hboxLayout = new QHBoxLayout;
    hboxLayout->addWidget(mTableView);
    hboxLayout->addLayout(vboxLayout);
    setLayout(hboxLayout);
}

void PluginDialog::onSelectionChanged()
{
    Plugin *plugin = currentPlugin();

    mLoadButton->setEnabled(plugin && !plugin->isLoaded());
    mUnloadButton->setEnabled(plugin && plugin->isLoaded());
}

void PluginDialog::onLoad()
{
    mApplication->pluginModel()->load(currentPlugin());
    mTableView->selectionModel()->clear();
}

void PluginDialog::onUnload()
{
    Plugin *plugin = currentPlugin();
    if (plugin->name() == ThisPlugin) {
        int response = QMessageBox::warning(
            this,
            tr("Warning"),
            tr("Unloading the pluginui plugin will close this dialog and make further changes impossible. Are you sure you want to unload this plugin?"),
            QMessageBox::Yes | QMessageBox::No
        );
        if (response == QMessageBox::No) {
            return;
        }
    }
    mApplication->pluginModel()->unload(plugin);
    if (plugin->name() != ThisPlugin) {
        mTableView->selectionModel()->clear();
    }
}

Plugin *PluginDialog::currentPlugin() const
{
    QModelIndexList selection(mTableView->selectionModel()->selectedIndexes());
    return selection.size() ? selection.at(0).data(Qt::UserRole).value<Plugin*>() : nullptr;
}
<|endoftext|>


<commit_before> // $Id$

 /**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * All rights reserved.                                                   *
 *                                                                        *
 * Primary Authors: Oystein Djuvsland                                     *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliHLTPHOSDigitMakerComponent.h"
#include "AliHLTCaloDigitMaker.h"
#include "AliHLTCaloDigitDataStruct.h"
#include "AliHLTPHOSMapper.h"
#include "AliHLTCaloChannelDataHeaderStruct.h"
#include "AliHLTCaloChannelDataStruct.h"
#include "AliPHOSEmcBadChannelsMap.h"
#include "AliPHOSEmcCalibData.h"
#include "TFile.h"
#include "AliCDBEntry.h"
#include "AliCDBPath.h"
#include "AliCDBManager.h"
#include <sys/stat.h>
#include <sys/types.h>

/**
 * @file   AliHLTPHOSDigitMakerComponent.cxx
 * @author Oystein Djuvsland
 * @date
 * @brief  A digit maker component for PHOS HLT
*/

// see below for class documentation
// or
// refer to README to build package
// or
// visit http://web.ift.uib.no/~kjeks/doc/alice-hlt

ClassImp(AliHLTPHOSDigitMakerComponent);

AliHLTPHOSDigitMakerComponent gAliHLTPHOSDigitMakerComponent;

AliHLTPHOSDigitMakerComponent::AliHLTPHOSDigitMakerComponent() :
  AliHLTCaloProcessor(),
  AliHLTCaloConstantsHandler("PHOS"),
  fDigitMakerPtr(0),
  fDigitContainerPtr(0),
  fBadChannelMap(0),
  fCalibData(0),
  fBCMInitialised(true),
  fGainsInitialised(true)
{
  //see header file for documentation
}

AliHLTPHOSDigitMakerComponent::~AliHLTPHOSDigitMakerComponent()
{
  //see header file for documentation
}

int
AliHLTPHOSDigitMakerComponent::Deinit()
{
  //see header file for documentation
  if(fDigitMakerPtr)
    {
      delete fDigitMakerPtr;
      fDigitMakerPtr = 0;
    }
  return 0;
}

const char*
AliHLTPHOSDigitMakerComponent::GetComponentID()
{
  //see header file for documentation
  return "PhosDigitMaker";
}

void
AliHLTPHOSDigitMakerComponent::GetInputDataTypes(vector<AliHLTComponentDataType>& list)
{
  //see header file for documentation
  list.clear();
  list.push_back(AliHLTPHOSDefinitions::fgkChannelDataType);
}

AliHLTComponentDataType
AliHLTPHOSDigitMakerComponent::GetOutputDataType()
{
  //see header file for documentation
  return AliHLTPHOSDefinitions::fgkDigitDataType;
}

void
AliHLTPHOSDigitMakerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
{
  //see header file for documentation
  constBase = 0;
  inputMultiplier = (float)sizeof(AliHLTCaloDigitDataStruct)/sizeof(AliHLTCaloChannelDataStruct) + 1;
}

int
AliHLTPHOSDigitMakerComponent::DoEvent(const AliHLTComponentEventData& evtData, const AliHLTComponentBlockData* blocks,
					AliHLTComponentTriggerData& /*trigData*/, AliHLTUInt8_t* outputPtr, AliHLTUInt32_t& size,
					std::vector<AliHLTComponentBlockData>& outputBlocks)
{
  //see header file for documentation
  UInt_t offset           = 0;
  UInt_t mysize           = 0;
  Int_t digitCount        = 0;
  Int_t ret               = 0;

  const AliHLTComponentBlockData* iter = 0;
  unsigned long ndx;

  UInt_t specification = 0;
  AliHLTCaloChannelDataHeaderStruct* tmpChannelData = 0;

  //  fDigitMakerPtr->SetDigitHeaderPtr(reinterpret_cast<AliHLTCaloDigitHeaderStruct*>(outputPtr));

  fDigitMakerPtr->SetDigitDataPtr(reinterpret_cast<AliHLTCaloDigitDataStruct*>(outputPtr));

  for( ndx = 0; ndx < evtData.fBlockCnt; ndx++ )
    {

      iter = blocks+ndx;

      if(iter->fDataType != AliHLTPHOSDefinitions::fgkChannelDataType)
	{
//	  HLTDebug("Data block is not of type fgkChannelDataType");
	  continue;
	}
      if(!fBCMInitialised)
      {
	 AliHLTPHOSMapper mapper;
	 Int_t module = mapper.GetModuleFromSpec(iter->fSpecification);
	 for(Int_t x = 0; x < fCaloConstants->GetNXCOLUMNSMOD(); x++)
	 {
	    for(Int_t z = 0; z < fCaloConstants->GetNZROWSMOD(); z++)
	    {
	       fDigitMakerPtr->SetBadChannel(x, z, fBadChannelMap->IsBadChannel(5-module, z+1, x+1));
	    }
	 }
	 //delete fBadChannelMap;
	 fBCMInitialised = true;
      }
      if(!fGainsInitialised)
      {
	 AliHLTPHOSMapper mapper;
	 Int_t module = mapper.GetModuleFromSpec(iter->fSpecification);
	 for(Int_t x = 0; x < fCaloConstants->GetNXCOLUMNSMOD(); x++)
	 {
	    for(Int_t z = 0; z < fCaloConstants->GetNZROWSMOD(); z++)
	    {
		fDigitMakerPtr->SetGain(x, z, fCalibData->GetHighLowRatioEmc(module, z+1, x+1), fCalibData->GetADCchannelEmc(module, z+1, x+1));
	    }
	 }
	 fGainsInitialised = true;
      }

      specification |= iter->fSpecification;
      tmpChannelData = reinterpret_cast<AliHLTCaloChannelDataHeaderStruct*>(iter->fPtr);

      ret = fDigitMakerPtr->MakeDigits(tmpChannelData, size-(digitCount*sizeof(AliHLTCaloDigitDataStruct)));
      if(ret == -1)
	{
	  HLTError("Trying to write over buffer size");
	  return -ENOBUFS;
	}
      digitCount += ret;
    }

  mysize += digitCount*sizeof(AliHLTCaloDigitDataStruct);

  HLTDebug("# of digits: %d, used memory size: %d, available size: %d", digitCount, mysize, size);

  if(mysize > 0)
    {
      AliHLTComponentBlockData bd;
      FillBlockData( bd );
      bd.fOffset = offset;
      bd.fSize = mysize;
      bd.fDataType = AliHLTPHOSDefinitions::fgkDigitDataType;
      bd.fSpecification = specification;
      outputBlocks.push_back(bd);
    }

  fDigitMakerPtr->Reset();

  size = mysize;

  return 0;
}

int
AliHLTPHOSDigitMakerComponent::DoInit(int argc, const char** argv )
{
  //see header file for documentation

  fDigitMakerPtr = new AliHLTCaloDigitMaker("PHOS");

  AliHLTCaloMapper *mapper = new AliHLTPHOSMapper();
  fDigitMakerPtr->SetMapper(mapper);

  Float_t mintime = 0.;
  Float_t maxtime =50.;

  for(int i = 0; i < argc; i++)
    {
      if(!strcmp("-lowgainfactor", argv[i]))
	{
	  fDigitMakerPtr->SetGlobalLowGainFactor(atof(argv[i+1]));
	}
      if(!strcmp("-highgainfactor", argv[i]))
	{
	  fDigitMakerPtr->SetGlobalHighGainFactor(atof(argv[i+1]));
	}
	if(!strcmp("-mintime", argv[i]))
	{
	   mintime = atof(argv[i+1]);
	}
	if(!strcmp("-maxtime", argv[i]))
	{
	   maxtime = atof(argv[i+1]);
	}
    }

 fDigitMakerPtr->SetTimeWindow(mintime, maxtime);

 if(GetBCMFromCDB()) return -1;
 if(GetGainsFromCDB()) return -1;

  //fDigitMakerPtr->SetDigitThreshold(2);

  return 0;
}

int AliHLTPHOSDigitMakerComponent::GetBCMFromCDB()
{
   fBCMInitialised = false;

//   HLTInfo("Getting bad channel map...");

  AliCDBPath path("PHOS","Calib","EmcBadChannels");
  if(path.GetPath())
    {
      //      HLTInfo("configure from entry %s", path.GetPath());
      AliCDBEntry *pEntry = AliCDBManager::Instance()->Get(path/*,GetRunNo()*/);
	if (pEntry)
	{
	    fBadChannelMap = (AliPHOSEmcBadChannelsMap*)pEntry->GetObject();
	}
      else
	{
	    HLTError("can not fetch object \"%s\" from CDB", path.GetPath());
	    return -1;
	}
    }
   if(!fBadChannelMap) return -1;
   return 0;
}

int AliHLTPHOSDigitMakerComponent::GetGainsFromCDB()
{
   fGainsInitialised = false;

//   HLTInfo("Getting bad channel map...");

  AliCDBPath path("PHOS","Calib","EmcGainPedestals");
  if(path.GetPath())
    {
      //      HLTInfo("configure from entry %s", path.GetPath());*/
      AliCDBEntry *pEntry = AliCDBManager::Instance()->Get(path/*,GetRunNo()*/);
      if (pEntry)
	{
	    fCalibData = (AliPHOSEmcCalibData*)pEntry->GetObject();
	}
      else
	{
	    HLTError("can not fetch object \"%s\" from CDB", path.GetPath());
	    return -1;
	}
    }

    if(!fCalibData) return -1;
   return 0;

}

AliHLTComponent*
AliHLTPHOSDigitMakerComponent::Spawn()
{
  //see header file for documentation
  return new AliHLTPHOSDigitMakerComponent();
}
<commit_msg>fixing warnings<commit_after> // $Id$

 /**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * All rights reserved.                                                   *
 *                                                                        *
 * Primary Authors: Oystein Djuvsland                                     *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliHLTPHOSDigitMakerComponent.h"
#include "AliHLTCaloDigitMaker.h"
#include "AliHLTCaloDigitDataStruct.h"
#include "AliHLTPHOSMapper.h"
#include "AliHLTCaloChannelDataHeaderStruct.h"
#include "AliHLTCaloChannelDataStruct.h"
#include "AliPHOSEmcBadChannelsMap.h"
#include "AliPHOSEmcCalibData.h"
#include "TFile.h"
#include "AliCDBEntry.h"
#include "AliCDBPath.h"
#include "AliCDBManager.h"
#include <sys/stat.h>
#include <sys/types.h>

/**
 * @file   AliHLTPHOSDigitMakerComponent.cxx
 * @author Oystein Djuvsland
 * @date
 * @brief  A digit maker component for PHOS HLT
*/

// see below for class documentation
// or
// refer to README to build package
// or
// visit http://web.ift.uib.no/~kjeks/doc/alice-hlt

ClassImp(AliHLTPHOSDigitMakerComponent);

AliHLTPHOSDigitMakerComponent gAliHLTPHOSDigitMakerComponent;

AliHLTPHOSDigitMakerComponent::AliHLTPHOSDigitMakerComponent() :
  AliHLTCaloProcessor(),
  AliHLTCaloConstantsHandler("PHOS"),
  fDigitMakerPtr(0),
  fDigitContainerPtr(0),
  fBadChannelMap(0),
  fCalibData(0),
  fBCMInitialised(true),
  fGainsInitialised(true)
{
  //see header file for documentation
}

AliHLTPHOSDigitMakerComponent::~AliHLTPHOSDigitMakerComponent()
{
  //see header file for documentation
}

int
AliHLTPHOSDigitMakerComponent::Deinit()
{
  //see header file for documentation
  if(fDigitMakerPtr)
    {
      delete fDigitMakerPtr;
      fDigitMakerPtr = 0;
    }
  return 0;
}

const char*
AliHLTPHOSDigitMakerComponent::GetComponentID()
{
  //see header file for documentation
  return "PhosDigitMaker";
}

void
AliHLTPHOSDigitMakerComponent::GetInputDataTypes(vector<AliHLTComponentDataType>& list)
{
  //see header file for documentation
  list.clear();
  list.push_back(AliHLTPHOSDefinitions::fgkChannelDataType);
}

AliHLTComponentDataType
AliHLTPHOSDigitMakerComponent::GetOutputDataType()
{
  //see header file for documentation
  return AliHLTPHOSDefinitions::fgkDigitDataType;
}

void
AliHLTPHOSDigitMakerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
{
  //see header file for documentation
  constBase = 0;
  inputMultiplier = (float)sizeof(AliHLTCaloDigitDataStruct)/sizeof(AliHLTCaloChannelDataStruct) + 1;
}

int
AliHLTPHOSDigitMakerComponent::DoEvent(const AliHLTComponentEventData& evtData, const AliHLTComponentBlockData* blocks,
					AliHLTComponentTriggerData& /*trigData*/, AliHLTUInt8_t* outputPtr, AliHLTUInt32_t& size,
					std::vector<AliHLTComponentBlockData>& outputBlocks)
{
  //see header file for documentation
  UInt_t offset           = 0;
  UInt_t mysize           = 0;
  Int_t digitCount        = 0;
  Int_t ret               = 0;

  const AliHLTComponentBlockData* iter = 0;
  unsigned long ndx;

  UInt_t specification = 0;
  AliHLTCaloChannelDataHeaderStruct* tmpChannelData = 0;

  //  fDigitMakerPtr->SetDigitHeaderPtr(reinterpret_cast<AliHLTCaloDigitHeaderStruct*>(outputPtr));

  fDigitMakerPtr->SetDigitDataPtr(reinterpret_cast<AliHLTCaloDigitDataStruct*>(outputPtr));

  for( ndx = 0; ndx < evtData.fBlockCnt; ndx++ )
    {

      iter = blocks+ndx;

      if(iter->fDataType != AliHLTPHOSDefinitions::fgkChannelDataType)
	{
//	  HLTDebug("Data block is not of type fgkChannelDataType");
	  continue;
	}
      if(!fBCMInitialised)
      {
	 AliHLTPHOSMapper mapper;
	 Int_t module = mapper.GetModuleFromSpec(iter->fSpecification);
	 for(Int_t x = 0; x < fCaloConstants->GetNXCOLUMNSMOD(); x++)
	 {
	    for(Int_t z = 0; z < fCaloConstants->GetNZROWSMOD(); z++)
	    {
	       fDigitMakerPtr->SetBadChannel(x, z, fBadChannelMap->IsBadChannel(5-module, z+1, x+1));
	    }
	 }
	 //delete fBadChannelMap;
	 fBCMInitialised = true;
      }
      if(!fGainsInitialised)
      {
	 AliHLTPHOSMapper mapper;
	 Int_t module = mapper.GetModuleFromSpec(iter->fSpecification);
	 for(Int_t x = 0; x < fCaloConstants->GetNXCOLUMNSMOD(); x++)
	 {
	    for(Int_t z = 0; z < fCaloConstants->GetNZROWSMOD(); z++)
	    {
		fDigitMakerPtr->SetGain(x, z, fCalibData->GetHighLowRatioEmc(module, z+1, x+1), fCalibData->GetADCchannelEmc(module, z+1, x+1));
	    }
	 }
	 fGainsInitialised = true;
      }

      specification |= iter->fSpecification;
      tmpChannelData = reinterpret_cast<AliHLTCaloChannelDataHeaderStruct*>(iter->fPtr);

      ret = fDigitMakerPtr->MakeDigits(tmpChannelData, size-(digitCount*sizeof(AliHLTCaloDigitDataStruct)));
      if(ret == -1)
	{
	  HLTError("Trying to write over buffer size");
	  return -ENOBUFS;
	}
      digitCount += ret;
    }

  mysize += digitCount*sizeof(AliHLTCaloDigitDataStruct);

  HLTDebug("# of digits: %d, used memory size: %d, available size: %d", digitCount, mysize, size);

  if(mysize > 0)
    {
      AliHLTComponentBlockData bd;
      FillBlockData( bd );
      bd.fOffset = offset;
      bd.fSize = mysize;
      bd.fDataType = AliHLTPHOSDefinitions::fgkDigitDataType;
      bd.fSpecification = specification;
      outputBlocks.push_back(bd);
    }

  fDigitMakerPtr->Reset();

  size = mysize;

  return 0;
}

int
AliHLTPHOSDigitMakerComponent::DoInit(int argc, const char** argv )
{
  //see header file for documentation

  fDigitMakerPtr = new AliHLTCaloDigitMaker("PHOS");

  AliHLTCaloMapper *mapper = new AliHLTPHOSMapper();
  fDigitMakerPtr->SetMapper(mapper);

  Float_t mintime = 0.;
  Float_t maxtime =50.;

  for(int i = 0; i < argc; i++)
    {
      if(!strcmp("-lowgainfactor", argv[i]))
	{
	  fDigitMakerPtr->SetGlobalLowGainFactor(atof(argv[i+1]));
	}
      if(!strcmp("-highgainfactor", argv[i]))
	{
	  fDigitMakerPtr->SetGlobalHighGainFactor(atof(argv[i+1]));
	}
	if(!strcmp("-mintime", argv[i]))
	{
	   mintime = atof(argv[i+1]);
	}
	if(!strcmp("-maxtime", argv[i]))
	{
	   maxtime = atof(argv[i+1]);
	}
    }

 fDigitMakerPtr->SetTimeWindow(mintime, maxtime);

 if(GetBCMFromCDB()) return -1;
 if(GetGainsFromCDB()) return -1;

  //fDigitMakerPtr->SetDigitThreshold(2);

  return 0;
}

int AliHLTPHOSDigitMakerComponent::GetBCMFromCDB()
{
   fBCMInitialised = false;

//   HLTInfo("Getting bad channel map...");

  AliCDBPath path("PHOS","Calib","EmcBadChannels");
  if(path.GetPath())
    {
      //      HLTInfo("configure from entry %s", path.GetPath());
      AliCDBEntry *pEntry = AliCDBManager::Instance()->Get(path/*,GetRunNo()*/);
	if (pEntry)
	{
	    fBadChannelMap = (AliPHOSEmcBadChannelsMap*)pEntry->GetObject();
	}
      else
	{
	    HLTError("can not fetch object \"%s\" from CDB", path.GetPath().Data());
	    return -1;
	}
    }
   if(!fBadChannelMap) return -1;
   return 0;
}

int AliHLTPHOSDigitMakerComponent::GetGainsFromCDB()
{
   fGainsInitialised = false;

//   HLTInfo("Getting bad channel map...");

  AliCDBPath path("PHOS","Calib","EmcGainPedestals");
  if(path.GetPath())
    {
      //      HLTInfo("configure from entry %s", path.GetPath());*/
      AliCDBEntry *pEntry = AliCDBManager::Instance()->Get(path/*,GetRunNo()*/);
      if (pEntry)
	{
	    fCalibData = (AliPHOSEmcCalibData*)pEntry->GetObject();
	}
      else
	{
	    HLTError("can not fetch object \"%s\" from CDB", path.GetPath().Data());
	    return -1;
	}
    }

    if(!fCalibData) return -1;
   return 0;

}

AliHLTComponent*
AliHLTPHOSDigitMakerComponent::Spawn()
{
  //see header file for documentation
  return new AliHLTPHOSDigitMakerComponent();
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qplatformdefs.h>

#include "qfilesystemwatcher.h"
#include "qfilesystemwatcher_kqueue_p.h"
#include "qcore_unix_p.h"

#include <qdebug.h>
#include <qfile.h>
#include <qsocketnotifier.h>
#include <qvarlengtharray.h>

#include <sys/types.h>
#include <sys/event.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>

QT_BEGIN_NAMESPACE

// #define KEVENT_DEBUG
#ifdef KEVENT_DEBUG
#  define DEBUG qDebug
#else
#  define DEBUG if(false)qDebug
#endif

QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create()
{
    int kqfd = kqueue();
    if (kqfd == -1)
        return 0;
    return new QKqueueFileSystemWatcherEngine(kqfd);
}

QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(int kqfd)
    : kqfd(kqfd)
{
    fcntl(kqfd, F_SETFD, FD_CLOEXEC);

    if (pipe(kqpipe) == -1) {
        perror("QKqueueFileSystemWatcherEngine: cannot create pipe");
        kqpipe[0] = kqpipe[1] = -1;
        return;
    }
    fcntl(kqpipe[0], F_SETFD, FD_CLOEXEC);
    fcntl(kqpipe[1], F_SETFD, FD_CLOEXEC);

    struct kevent kev;
    EV_SET(&kev,
           kqpipe[0],
           EVFILT_READ,
           EV_ADD | EV_ENABLE,
           0,
           0,
           0);
    if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
        perror("QKqueueFileSystemWatcherEngine: cannot watch pipe, kevent returned");
        return;
    }
}

QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine()
{
    stop();
    wait();

    close(kqfd);
    close(kqpipe[0]);
    close(kqpipe[1]);

    foreach (int id, pathToID.values())
        ::close(id < 0 ? -id : id);
}

QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths,
                                                     QStringList *files,
                                                     QStringList *directories)
{
    QMutexLocker locker(&mutex);

    QStringList p = paths;
    QMutableListIterator<QString> it(p);
    while (it.hasNext()) {
        QString path = it.next();
        int fd;
#if defined(O_EVTONLY)
        fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY);
#else
        fd = qt_safe_open(QFile::encodeName(path), O_RDONLY);
#endif
        if (fd == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: open");
            continue;
        }

        QT_STATBUF st;
        if (QT_FSTAT(fd, &st) == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: fstat");
            ::close(fd);
            continue;
        }
        int id = (S_ISDIR(st.st_mode)) ? -fd : fd;
        if (id < 0) {
            if (directories->contains(path)) {
                ::close(fd);
                continue;
            }
        } else {
            if (files->contains(path)) {
                ::close(fd);
                continue;
            }
        }

        struct kevent kev;
        EV_SET(&kev,
               fd,
               EVFILT_VNODE,
               EV_ADD | EV_ENABLE | EV_ONESHOT,
               NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
               0,
               0);
        if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: kevent");
            ::close(fd);
            continue;
        }

        it.remove();
        if (id < 0) {
            DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path;
            directories->append(path);
        } else {
            DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path;
            files->append(path);
        }

        pathToID.insert(path, id);
        idToPath.insert(id, path);
    }

    if (!isRunning())
        start();
    else
        write(kqpipe[1], "@", 1);

    return p;
}

QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths,
                                                        QStringList *files,
                                                        QStringList *directories)
{
    QMutexLocker locker(&mutex);

    QStringList p = paths;
    QMutableListIterator<QString> it(p);
    while (it.hasNext()) {
        QString path = it.next();
        int id = pathToID.take(path);
        QString x = idToPath.take(id);
        if (x.isEmpty() || x != path)
            continue;

        int fd = id < 0 ? -id : id;
        struct kevent kev;
        EV_SET(&kev,
               fd,
               EVFILT_VNODE,
               EV_DELETE,
               NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
               0,
               0);
        if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
            perror("QKqueueFileSystemWatcherEngine::removeWatch: kevent");
        }
        ::close(fd);

        it.remove();
        if (id < 0)
            directories->removeAll(path);
        else
            files->removeAll(path);
    }

    if (pathToID.isEmpty()) {
        stop();
        locker.unlock();
        wait();
        locker.relock();
    } else {
        write(kqpipe[1], "@", 1);
    }

    return p;
}

void QKqueueFileSystemWatcherEngine::stop()
{
    write(kqpipe[1], "q", 1);
}

void QKqueueFileSystemWatcherEngine::run()
{
    static const struct timespec ZeroTimeout = { 0, 0 };

    forever {
        struct kevent kev;
        DEBUG() << "QKqueueFileSystemWatcherEngine: waiting for kevents...";
        int r = kevent(kqfd, 0, 0, &kev, 1, 0);
        if (r < 0) {
            perror("QKqueueFileSystemWatcherEngine: error during kevent wait");
            return;
        }

        QMutexLocker locker(&mutex);
        do {
            int fd = kev.ident;

            DEBUG() << "QKqueueFileSystemWatcherEngine: processing kevent" << kev.ident << kev.filter;
            if (fd == kqpipe[0]) {
                char c;
                if (read(kqpipe[0], &c, 1) != 1) {
                    perror("QKqueueFileSystemWatcherEngine: error reading from pipe");
                    return;
                }
                switch (c) {
                case 'q':
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received 'q', exiting...";
                    return;
                case '@':
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received '@', continuing...";
                    break;
                default:
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received unknow message" << c;
                    break;
                }
            } else {
                int id = fd;
                QString path = idToPath.value(id);
                if (path.isEmpty()) {
                    // perhaps a directory?
                    id = -id;
                    path = idToPath.value(id);
                    if (path.isEmpty()) {
                        DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching";
                        continue;
                    }
                }
                if (kev.filter != EVFILT_VNODE) {
                    DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter";
                    continue;
                }

                if ((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) {
                    DEBUG() << path << "removed, removing watch also";

                    pathToID.remove(path);
                    idToPath.remove(id);
                    ::close(fd);

                    if (id < 0)
                        emit directoryChanged(path, true);
                    else
                        emit fileChanged(path, true);
                } else {
                    DEBUG() << path << "changed, re-enabling watch";

                    if (id < 0)
                        emit directoryChanged(path, false);
                    else
                        emit fileChanged(path, false);

                    // renable the watch
                    EV_SET(&kev,
                           fd,
                           EVFILT_VNODE,
                           EV_ADD | EV_ENABLE | EV_ONESHOT,
                           NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
                           0,
                           0);
                    if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
                        perror("QKqueueFileSystemWatcherEngine::processKqueueEvents: kevent EV_ADD");
                    }
                }
            }

            // are there any more?
            r = kevent(kqfd, 0, 0, &kev, 1, &ZeroTimeout);
        } while (r > 0);
    }
}

QT_END_NAMESPACE
<commit_msg>Correct #include path for qcore_unix_p.h<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qplatformdefs.h>

#include "qfilesystemwatcher.h"
#include "qfilesystemwatcher_kqueue_p.h"
#include "private/qcore_unix_p.h"

#include <qdebug.h>
#include <qfile.h>
#include <qsocketnotifier.h>
#include <qvarlengtharray.h>

#include <sys/types.h>
#include <sys/event.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>

QT_BEGIN_NAMESPACE

// #define KEVENT_DEBUG
#ifdef KEVENT_DEBUG
#  define DEBUG qDebug
#else
#  define DEBUG if(false)qDebug
#endif

QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create()
{
    int kqfd = kqueue();
    if (kqfd == -1)
        return 0;
    return new QKqueueFileSystemWatcherEngine(kqfd);
}

QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(int kqfd)
    : kqfd(kqfd)
{
    fcntl(kqfd, F_SETFD, FD_CLOEXEC);

    if (pipe(kqpipe) == -1) {
        perror("QKqueueFileSystemWatcherEngine: cannot create pipe");
        kqpipe[0] = kqpipe[1] = -1;
        return;
    }
    fcntl(kqpipe[0], F_SETFD, FD_CLOEXEC);
    fcntl(kqpipe[1], F_SETFD, FD_CLOEXEC);

    struct kevent kev;
    EV_SET(&kev,
           kqpipe[0],
           EVFILT_READ,
           EV_ADD | EV_ENABLE,
           0,
           0,
           0);
    if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
        perror("QKqueueFileSystemWatcherEngine: cannot watch pipe, kevent returned");
        return;
    }
}

QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine()
{
    stop();
    wait();

    close(kqfd);
    close(kqpipe[0]);
    close(kqpipe[1]);

    foreach (int id, pathToID.values())
        ::close(id < 0 ? -id : id);
}

QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths,
                                                     QStringList *files,
                                                     QStringList *directories)
{
    QMutexLocker locker(&mutex);

    QStringList p = paths;
    QMutableListIterator<QString> it(p);
    while (it.hasNext()) {
        QString path = it.next();
        int fd;
#if defined(O_EVTONLY)
        fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY);
#else
        fd = qt_safe_open(QFile::encodeName(path), O_RDONLY);
#endif
        if (fd == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: open");
            continue;
        }

        QT_STATBUF st;
        if (QT_FSTAT(fd, &st) == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: fstat");
            ::close(fd);
            continue;
        }
        int id = (S_ISDIR(st.st_mode)) ? -fd : fd;
        if (id < 0) {
            if (directories->contains(path)) {
                ::close(fd);
                continue;
            }
        } else {
            if (files->contains(path)) {
                ::close(fd);
                continue;
            }
        }

        struct kevent kev;
        EV_SET(&kev,
               fd,
               EVFILT_VNODE,
               EV_ADD | EV_ENABLE | EV_ONESHOT,
               NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
               0,
               0);
        if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: kevent");
            ::close(fd);
            continue;
        }

        it.remove();
        if (id < 0) {
            DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path;
            directories->append(path);
        } else {
            DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path;
            files->append(path);
        }

        pathToID.insert(path, id);
        idToPath.insert(id, path);
    }

    if (!isRunning())
        start();
    else
        write(kqpipe[1], "@", 1);

    return p;
}

QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths,
                                                        QStringList *files,
                                                        QStringList *directories)
{
    QMutexLocker locker(&mutex);

    QStringList p = paths;
    QMutableListIterator<QString> it(p);
    while (it.hasNext()) {
        QString path = it.next();
        int id = pathToID.take(path);
        QString x = idToPath.take(id);
        if (x.isEmpty() || x != path)
            continue;

        int fd = id < 0 ? -id : id;
        struct kevent kev;
        EV_SET(&kev,
               fd,
               EVFILT_VNODE,
               EV_DELETE,
               NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
               0,
               0);
        if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
            perror("QKqueueFileSystemWatcherEngine::removeWatch: kevent");
        }
        ::close(fd);

        it.remove();
        if (id < 0)
            directories->removeAll(path);
        else
            files->removeAll(path);
    }

    if (pathToID.isEmpty()) {
        stop();
        locker.unlock();
        wait();
        locker.relock();
    } else {
        write(kqpipe[1], "@", 1);
    }

    return p;
}

void QKqueueFileSystemWatcherEngine::stop()
{
    write(kqpipe[1], "q", 1);
}

void QKqueueFileSystemWatcherEngine::run()
{
    static const struct timespec ZeroTimeout = { 0, 0 };

    forever {
        struct kevent kev;
        DEBUG() << "QKqueueFileSystemWatcherEngine: waiting for kevents...";
        int r = kevent(kqfd, 0, 0, &kev, 1, 0);
        if (r < 0) {
            perror("QKqueueFileSystemWatcherEngine: error during kevent wait");
            return;
        }

        QMutexLocker locker(&mutex);
        do {
            int fd = kev.ident;

            DEBUG() << "QKqueueFileSystemWatcherEngine: processing kevent" << kev.ident << kev.filter;
            if (fd == kqpipe[0]) {
                char c;
                if (read(kqpipe[0], &c, 1) != 1) {
                    perror("QKqueueFileSystemWatcherEngine: error reading from pipe");
                    return;
                }
                switch (c) {
                case 'q':
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received 'q', exiting...";
                    return;
                case '@':
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received '@', continuing...";
                    break;
                default:
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received unknow message" << c;
                    break;
                }
            } else {
                int id = fd;
                QString path = idToPath.value(id);
                if (path.isEmpty()) {
                    // perhaps a directory?
                    id = -id;
                    path = idToPath.value(id);
                    if (path.isEmpty()) {
                        DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching";
                        continue;
                    }
                }
                if (kev.filter != EVFILT_VNODE) {
                    DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter";
                    continue;
                }

                if ((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) {
                    DEBUG() << path << "removed, removing watch also";

                    pathToID.remove(path);
                    idToPath.remove(id);
                    ::close(fd);

                    if (id < 0)
                        emit directoryChanged(path, true);
                    else
                        emit fileChanged(path, true);
                } else {
                    DEBUG() << path << "changed, re-enabling watch";

                    if (id < 0)
                        emit directoryChanged(path, false);
                    else
                        emit fileChanged(path, false);

                    // renable the watch
                    EV_SET(&kev,
                           fd,
                           EVFILT_VNODE,
                           EV_ADD | EV_ENABLE | EV_ONESHOT,
                           NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
                           0,
                           0);
                    if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
                        perror("QKqueueFileSystemWatcherEngine::processKqueueEvents: kevent EV_ADD");
                    }
                }
            }

            // are there any more?
            r = kevent(kqfd, 0, 0, &kev, 1, &ZeroTimeout);
        } while (r > 0);
    }
}

QT_END_NAMESPACE
<|endoftext|>