<commit_before>/*****************************************************************************
 * main.cpp: ActiveX control for VLC
 *****************************************************************************
 * Copyright (C) 2005 the VideoLAN team
 *
 * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "plugin.h"
#include "utils.h"

#include <stdio.h>

#include <comcat.h>
#include <windows.h>
#include <shlwapi.h>

#include <tchar.h>

#include <_mingw.h>

#ifdef __MINGW64_VERSION_MAJOR

#include <guiddef.h>
#include <objsafe.h>

#else /* ! __MINGW64_VERSION_MAJOR */

/*
** Widl generated code requires guiddef.h,
** which is not available under MinGW32
*/
#undef GUID_EXT
#define GUID_EXT
#include <initguid.h>

/*
** Mingw32 do not declare those
*/
static DEFINE_GUID(CATID_SafeForInitializing, \
	0x7DD95802, 0x9882, 0x11CF, 0x9F, 0xA9, 0x00,0xAA,0x00,0x6C,0x42,0xC4);
static DEFINE_GUID(CATID_SafeForScripting, \
	0x7DD95801, 0x9882, 0x11CF, 0x9F, 0xA9, 0x00,0xAA,0x00,0x6C,0x42,0xC4);

#endif /* __MINGW64_VERSION_MAJOR */

using namespace std;

#define COMPANY_STR "VideoLAN"
#define PROGRAM_STR "VLCPlugin"
#define DESCRIPTION "VLC ActiveX Plugin and IE Web Plugin"

#define THREADING_MODEL "Apartment"
#define MISC_STATUS     "131473"

#define PROGID_STR COMPANY_STR"."PROGRAM_STR

#define GUID_STRLEN 39

static LONG i_class_ref= 0;
static HINSTANCE h_instance= 0;

HMODULE DllGetModule()
{
    return h_instance;
};

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
    HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;

    *ppv = NULL;

    if( (CLSID_VLCPlugin == rclsid) || (CLSID_VLCPlugin2 == rclsid) )
    {
        VLCPluginClass *plugin =
            new VLCPluginClass(&i_class_ref, h_instance, rclsid);
        hr = plugin->QueryInterface(riid, ppv);
        plugin->Release();
    }
    return hr;
};

STDAPI DllCanUnloadNow(VOID)
{
    return (0 == i_class_ref) ? S_OK: S_FALSE;
};

static inline HKEY keyCreate(HKEY parentKey, LPCTSTR keyName)
{
    HKEY childKey;
    if( ERROR_SUCCESS == RegCreateKeyEx(parentKey, keyName, 0, NULL,
             REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &childKey, NULL) )
    {
        return childKey;
    }
    return NULL;
};

static inline HKEY keySet(HKEY hKey, LPCTSTR valueName,
                          const void *s, size_t len, DWORD dwType = REG_SZ)
{
    if( NULL != hKey )
    {
        RegSetValueEx(hKey, valueName, 0, dwType, (const BYTE*)s, len);
    }
    return hKey;
};

static inline HKEY keySetDef(HKEY hKey,
                             const void *s, size_t len, DWORD dwType = REG_SZ)
{
    return keySet(hKey, NULL, s, len, dwType);
};

static inline HKEY keySetDef(HKEY hKey, LPCTSTR s)
{
    return keySetDef(hKey, s, sizeof(TCHAR)*(_tcslen(s)+1), REG_SZ);
};

static inline HKEY keyClose(HKEY hKey)
{
    if( NULL != hKey )
    {
        RegCloseKey(hKey);
    }
    return NULL;
};

static void UnregisterProgID(REFCLSID rclsid, unsigned int version)
{
    OLECHAR szCLSID[GUID_STRLEN];

    StringFromGUID2(rclsid, szCLSID, GUID_STRLEN);

    TCHAR progId[sizeof(PROGID_STR)+16];
    _stprintf(progId, TEXT("%s.%u"), TEXT(PROGID_STR), version);

    SHDeleteKey(HKEY_CLASSES_ROOT, progId);

    HKEY hClsIDKey;
    if( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_WRITE, &hClsIDKey) )
    {
        SHDeleteKey(hClsIDKey, szCLSID);
        RegCloseKey(hClsIDKey);
    }
};

STDAPI DllUnregisterServer(VOID)
{
    // unregister type lib from the registry
    UnRegisterTypeLib(LIBID_AXVLC, 1, 0, LOCALE_NEUTRAL, SYS_WIN32);

    // remove component categories we supports
    ICatRegister *pcr;
    if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr,
            NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
        CATID implCategories[] = {
            CATID_Control,
            CATID_PersistsToPropertyBag,
            CATID_InternetAware,
            CATID_SafeForInitializing,
            CATID_SafeForScripting,
        };

        pcr->UnRegisterClassImplCategories(CLSID_VLCPlugin,
                sizeof(implCategories)/sizeof(CATID), implCategories);
        pcr->UnRegisterClassImplCategories(CLSID_VLCPlugin2,
                sizeof(implCategories)/sizeof(CATID), implCategories);
        pcr->Release();
    }

    SHDeleteKey(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));

    UnregisterProgID(CLSID_VLCPlugin, 2);
    UnregisterProgID(CLSID_VLCPlugin2, 1);

    return S_OK;
};

static HRESULT RegisterClassID(HKEY hParent, REFCLSID rclsid, unsigned int version, BOOL isDefault, LPCTSTR path, size_t pathLen)
{
    TCHAR progId[sizeof(PROGID_STR)+16];
    _stprintf(progId, TEXT("%s.%u"), TEXT(PROGID_STR), version);

    TCHAR description[sizeof(DESCRIPTION)+16];
    _stprintf(description, TEXT("%s v%u"), TEXT(DESCRIPTION), version);

    HKEY hClassKey;
    {
        OLECHAR szCLSID[GUID_STRLEN];

        StringFromGUID2(rclsid, szCLSID, GUID_STRLEN);

        HKEY hProgKey = keyCreate(HKEY_CLASSES_ROOT, progId);
        if( NULL != hProgKey )
        {
            // default key value
            keySetDef(hProgKey, description);

            keyClose(keySetDef(keyCreate(hProgKey, TEXT("CLSID")),
                               szCLSID, sizeof(szCLSID)));

            //hSubKey = keyClose(keyCreate(hBaseKey, "Insertable"));

            RegCloseKey(hProgKey);
        }
        if( isDefault )
        {
            hProgKey = keyCreate(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));
            if( NULL != hProgKey )
            {
                // default key value
                keySetDef(hProgKey, description);

                keyClose(keySetDef(keyCreate(hProgKey, TEXT("CLSID")),
                                   szCLSID, sizeof(szCLSID)));

                keyClose(keySetDef(keyCreate(hProgKey, TEXT("CurVer")),
                                   progId));
            }
        }
        hClassKey = keyCreate(hParent, szCLSID);
    }
    if( NULL != hClassKey )
    {
        // default key value
        keySetDef(hClassKey, description);

        // Control key value
        keyClose(keyCreate(hClassKey, TEXT("Control")));

        // Insertable key value
        //keyClose(keyCreate(hClassKey, TEXT("Insertable")));

        // ToolboxBitmap32 key value
        {
            TCHAR iconPath[pathLen+3];
            memcpy(iconPath, path, sizeof(TCHAR)*pathLen);
            _tcscpy(iconPath+pathLen, TEXT(",1"));
            keyClose(keySetDef(keyCreate(hClassKey,
                TEXT("ToolboxBitmap32")),
                iconPath, sizeof(iconPath)));
        }

#ifdef BUILD_LOCALSERVER
        // LocalServer32 key value
        keyClose(keySetDef(keyCreate(hClassKey,
            TEXT("LocalServer32"), path, sizeof(TCHAR)*(pathLen+1))));
#else
        // InprocServer32 key value
        {
            HKEY hSubKey = keySetDef(keyCreate(hClassKey,
                TEXT("InprocServer32")),
                path, sizeof(TCHAR)*(pathLen+1));
            keySet(hSubKey,
                TEXT("ThreadingModel"),
                TEXT(THREADING_MODEL), sizeof(TEXT(THREADING_MODEL)));
            keyClose(hSubKey);
        }
#endif

        // MiscStatus key value
        keyClose(keySetDef(keyCreate(hClassKey,TEXT("MiscStatus\\1")),
                           TEXT(MISC_STATUS), sizeof(TEXT(MISC_STATUS))));

        // Programmable key value
        keyClose(keyCreate(hClassKey, TEXT("Programmable")));

        // ProgID key value
        keyClose(keySetDef(keyCreate(hClassKey,TEXT("ProgID")),progId));

        // VersionIndependentProgID key value
        keyClose(keySetDef(keyCreate(hClassKey,
                                     TEXT("VersionIndependentProgID")),
                           TEXT(PROGID_STR), sizeof(TEXT(PROGID_STR))));

        // Version key value
        keyClose(keySetDef(keyCreate(hClassKey,TEXT("Version")),TEXT("1.0")));

        // TypeLib key value
        OLECHAR szLIBID[GUID_STRLEN];

        StringFromGUID2(LIBID_AXVLC, szLIBID, GUID_STRLEN);

        keyClose(keySetDef(keyCreate(hClassKey,TEXT("TypeLib")),
                           szLIBID, sizeof(szLIBID)));

        RegCloseKey(hClassKey);
    }
    return S_OK;
}

STDAPI DllRegisterServer(VOID)
{
    DllUnregisterServer();

    TCHAR DllPath[MAX_PATH];
    DWORD DllPathLen=GetModuleFileName(h_instance, DllPath, MAX_PATH) ;
    if( 0 == DllPathLen )
        return E_UNEXPECTED;
    DllPath[MAX_PATH-1] = '\0';

    HKEY hBaseKey;

    if( ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"),
                                      0, KEY_CREATE_SUB_KEY, &hBaseKey) )
        return SELFREG_E_CLASS;

    RegisterClassID(hBaseKey, CLSID_VLCPlugin, 1, FALSE, DllPath, DllPathLen);
    RegisterClassID(hBaseKey, CLSID_VLCPlugin2, 2, TRUE, DllPath, DllPathLen);

    RegCloseKey(hBaseKey);

    // indicate which component categories we support
    ICatRegister *pcr;
    if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr,
            NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
        CATID implCategories[] = {
            CATID_Control,
            CATID_PersistsToPropertyBag,
            CATID_InternetAware,
            CATID_SafeForInitializing,
            CATID_SafeForScripting,
        };

        pcr->RegisterClassImplCategories(CLSID_VLCPlugin,
                sizeof(implCategories)/sizeof(CATID), implCategories);
        pcr->RegisterClassImplCategories(CLSID_VLCPlugin2,
                sizeof(implCategories)/sizeof(CATID), implCategories);
        pcr->Release();
    }

#ifdef BUILD_LOCALSERVER
    // replace .exe by .tlb
    _tcscpy(DllPath+DllPathLen-4, TEXT(".tlb"));
#endif

    // register type lib into the registry
    ITypeLib *typeLib;

    HRESULT result = LoadTypeLibEx(DllPath, REGKIND_REGISTER, &typeLib);
    if( SUCCEEDED(result) )
        typeLib->Release();

    return result;
};

#ifdef BUILD_LOCALSERVER

/*
** easier to debug an application than a DLL on cygwin GDB :)
*/
#include <iostream>

STDAPI_(int) WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
    MSG msg;

    if( FAILED(OleInitialize(NULL)) )
    {
        cerr << "cannot initialize OLE" << endl;
        return 1;
    }

    h_instance = hInst;

    if( FAILED(DllRegisterServer()) )
    {
        cerr << "cannot register Local Server" << endl;
        return 1;
    }

    IUnknown *classProc = NULL;

    if( FAILED(DllGetClassObject(CLSID_VLCPlugin, IID_IUnknown,
                                 (LPVOID *)&classProc)) )
        return 0;

    DWORD dwRegisterClassObject;
    DWORD dwRegisterClassObject2;

    if( FAILED(CoRegisterClassObject(CLSID_VLCPlugin, classProc,
        CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegisterClassObject)) )
        return 0;

    DWORD dwRegisterActiveObject;

    if( FAILED(RegisterActiveObject(classProc, CLSID_VLCPlugin,
                    ACTIVEOBJECT_WEAK, &dwRegisterActiveObject)) )
        return 0;

    if( FAILED(RegisterActiveObject(classProc, CLSID_VLCPlugin2,
                    ACTIVEOBJECT_WEAK, &dwRegisterActiveObject2)) )
        return 0;

    classProc->Release();

    /*
    * Polling messages from event queue
    */
    while( S_FALSE == DllCanUnloadNow() )
    {
        while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
        {
            if( msg.message == WM_QUIT )
                break;  // break out PeekMessage loop

            /*if(TranslateAccelerator(ghwndApp, ghAccel, &msg))
                continue;*/

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if(msg.message == WM_QUIT)
            break;  // break out main loop

        WaitMessage();
    }

    if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject, NULL)) )
        CoRevokeClassObject(dwRegisterClassObject);

    if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject2, NULL)) )
        CoRevokeClassObject(dwRegisterClassObject2);

    // Reached on WM_QUIT message
    OleUninitialize();
    return ((int) msg.wParam);
};

#else

STDAPI_(BOOL) DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved )
{
    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
            h_instance = (HINSTANCE)hModule;
            break;

        default:
            break;
    }
    return TRUE;
};

#endif

<commit_msg>mingw32: fix CATID_InternetAware<commit_after>/*****************************************************************************
 * main.cpp: ActiveX control for VLC
 *****************************************************************************
 * Copyright (C) 2005 the VideoLAN team
 *
 * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "plugin.h"
#include "utils.h"

#include <stdio.h>

#include <comcat.h>
#include <windows.h>
#include <shlwapi.h>

#include <tchar.h>

#include <_mingw.h>

#ifdef __MINGW64_VERSION_MAJOR

#include <guiddef.h>
#include <objsafe.h>

#else /* ! __MINGW64_VERSION_MAJOR */

/*
** Widl generated code requires guiddef.h,
** which is not available under MinGW32
*/
#undef GUID_EXT
#define GUID_EXT
#include <initguid.h>

/*
** Mingw32 do not declare those
*/
/* CATID_InternetAware is declared as extern but not present in library */
DEFINE_GUID(CATID_InternetAware, \
    0x0DE86A58, 0x2BAA, 0x11CF, 0xA2, 0x29, 0x00,0xAA,0x00,0x3D,0x73,0x52);
static DEFINE_GUID(CATID_SafeForInitializing, \
	0x7DD95802, 0x9882, 0x11CF, 0x9F, 0xA9, 0x00,0xAA,0x00,0x6C,0x42,0xC4);
static DEFINE_GUID(CATID_SafeForScripting, \
	0x7DD95801, 0x9882, 0x11CF, 0x9F, 0xA9, 0x00,0xAA,0x00,0x6C,0x42,0xC4);

#endif /* __MINGW64_VERSION_MAJOR */

using namespace std;

#define COMPANY_STR "VideoLAN"
#define PROGRAM_STR "VLCPlugin"
#define DESCRIPTION "VLC ActiveX Plugin and IE Web Plugin"

#define THREADING_MODEL "Apartment"
#define MISC_STATUS     "131473"

#define PROGID_STR COMPANY_STR"."PROGRAM_STR

#define GUID_STRLEN 39

static LONG i_class_ref= 0;
static HINSTANCE h_instance= 0;

HMODULE DllGetModule()
{
    return h_instance;
};

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
    HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;

    *ppv = NULL;

    if( (CLSID_VLCPlugin == rclsid) || (CLSID_VLCPlugin2 == rclsid) )
    {
        VLCPluginClass *plugin =
            new VLCPluginClass(&i_class_ref, h_instance, rclsid);
        hr = plugin->QueryInterface(riid, ppv);
        plugin->Release();
    }
    return hr;
};

STDAPI DllCanUnloadNow(VOID)
{
    return (0 == i_class_ref) ? S_OK: S_FALSE;
};

static inline HKEY keyCreate(HKEY parentKey, LPCTSTR keyName)
{
    HKEY childKey;
    if( ERROR_SUCCESS == RegCreateKeyEx(parentKey, keyName, 0, NULL,
             REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &childKey, NULL) )
    {
        return childKey;
    }
    return NULL;
};

static inline HKEY keySet(HKEY hKey, LPCTSTR valueName,
                          const void *s, size_t len, DWORD dwType = REG_SZ)
{
    if( NULL != hKey )
    {
        RegSetValueEx(hKey, valueName, 0, dwType, (const BYTE*)s, len);
    }
    return hKey;
};

static inline HKEY keySetDef(HKEY hKey,
                             const void *s, size_t len, DWORD dwType = REG_SZ)
{
    return keySet(hKey, NULL, s, len, dwType);
};

static inline HKEY keySetDef(HKEY hKey, LPCTSTR s)
{
    return keySetDef(hKey, s, sizeof(TCHAR)*(_tcslen(s)+1), REG_SZ);
};

static inline HKEY keyClose(HKEY hKey)
{
    if( NULL != hKey )
    {
        RegCloseKey(hKey);
    }
    return NULL;
};

static void UnregisterProgID(REFCLSID rclsid, unsigned int version)
{
    OLECHAR szCLSID[GUID_STRLEN];

    StringFromGUID2(rclsid, szCLSID, GUID_STRLEN);

    TCHAR progId[sizeof(PROGID_STR)+16];
    _stprintf(progId, TEXT("%s.%u"), TEXT(PROGID_STR), version);

    SHDeleteKey(HKEY_CLASSES_ROOT, progId);

    HKEY hClsIDKey;
    if( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_WRITE, &hClsIDKey) )
    {
        SHDeleteKey(hClsIDKey, szCLSID);
        RegCloseKey(hClsIDKey);
    }
};

STDAPI DllUnregisterServer(VOID)
{
    // unregister type lib from the registry
    UnRegisterTypeLib(LIBID_AXVLC, 1, 0, LOCALE_NEUTRAL, SYS_WIN32);

    // remove component categories we supports
    ICatRegister *pcr;
    if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr,
            NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
        CATID implCategories[] = {
            CATID_Control,
            CATID_PersistsToPropertyBag,
            CATID_InternetAware,
            CATID_SafeForInitializing,
            CATID_SafeForScripting,
        };

        pcr->UnRegisterClassImplCategories(CLSID_VLCPlugin,
                sizeof(implCategories)/sizeof(CATID), implCategories);
        pcr->UnRegisterClassImplCategories(CLSID_VLCPlugin2,
                sizeof(implCategories)/sizeof(CATID), implCategories);
        pcr->Release();
    }

    SHDeleteKey(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));

    UnregisterProgID(CLSID_VLCPlugin, 2);
    UnregisterProgID(CLSID_VLCPlugin2, 1);

    return S_OK;
};

static HRESULT RegisterClassID(HKEY hParent, REFCLSID rclsid, unsigned int version, BOOL isDefault, LPCTSTR path, size_t pathLen)
{
    TCHAR progId[sizeof(PROGID_STR)+16];
    _stprintf(progId, TEXT("%s.%u"), TEXT(PROGID_STR), version);

    TCHAR description[sizeof(DESCRIPTION)+16];
    _stprintf(description, TEXT("%s v%u"), TEXT(DESCRIPTION), version);

    HKEY hClassKey;
    {
        OLECHAR szCLSID[GUID_STRLEN];

        StringFromGUID2(rclsid, szCLSID, GUID_STRLEN);

        HKEY hProgKey = keyCreate(HKEY_CLASSES_ROOT, progId);
        if( NULL != hProgKey )
        {
            // default key value
            keySetDef(hProgKey, description);

            keyClose(keySetDef(keyCreate(hProgKey, TEXT("CLSID")),
                               szCLSID, sizeof(szCLSID)));

            //hSubKey = keyClose(keyCreate(hBaseKey, "Insertable"));

            RegCloseKey(hProgKey);
        }
        if( isDefault )
        {
            hProgKey = keyCreate(HKEY_CLASSES_ROOT, TEXT(PROGID_STR));
            if( NULL != hProgKey )
            {
                // default key value
                keySetDef(hProgKey, description);

                keyClose(keySetDef(keyCreate(hProgKey, TEXT("CLSID")),
                                   szCLSID, sizeof(szCLSID)));

                keyClose(keySetDef(keyCreate(hProgKey, TEXT("CurVer")),
                                   progId));
            }
        }
        hClassKey = keyCreate(hParent, szCLSID);
    }
    if( NULL != hClassKey )
    {
        // default key value
        keySetDef(hClassKey, description);

        // Control key value
        keyClose(keyCreate(hClassKey, TEXT("Control")));

        // Insertable key value
        //keyClose(keyCreate(hClassKey, TEXT("Insertable")));

        // ToolboxBitmap32 key value
        {
            TCHAR iconPath[pathLen+3];
            memcpy(iconPath, path, sizeof(TCHAR)*pathLen);
            _tcscpy(iconPath+pathLen, TEXT(",1"));
            keyClose(keySetDef(keyCreate(hClassKey,
                TEXT("ToolboxBitmap32")),
                iconPath, sizeof(iconPath)));
        }

#ifdef BUILD_LOCALSERVER
        // LocalServer32 key value
        keyClose(keySetDef(keyCreate(hClassKey,
            TEXT("LocalServer32"), path, sizeof(TCHAR)*(pathLen+1))));
#else
        // InprocServer32 key value
        {
            HKEY hSubKey = keySetDef(keyCreate(hClassKey,
                TEXT("InprocServer32")),
                path, sizeof(TCHAR)*(pathLen+1));
            keySet(hSubKey,
                TEXT("ThreadingModel"),
                TEXT(THREADING_MODEL), sizeof(TEXT(THREADING_MODEL)));
            keyClose(hSubKey);
        }
#endif

        // MiscStatus key value
        keyClose(keySetDef(keyCreate(hClassKey,TEXT("MiscStatus\\1")),
                           TEXT(MISC_STATUS), sizeof(TEXT(MISC_STATUS))));

        // Programmable key value
        keyClose(keyCreate(hClassKey, TEXT("Programmable")));

        // ProgID key value
        keyClose(keySetDef(keyCreate(hClassKey,TEXT("ProgID")),progId));

        // VersionIndependentProgID key value
        keyClose(keySetDef(keyCreate(hClassKey,
                                     TEXT("VersionIndependentProgID")),
                           TEXT(PROGID_STR), sizeof(TEXT(PROGID_STR))));

        // Version key value
        keyClose(keySetDef(keyCreate(hClassKey,TEXT("Version")),TEXT("1.0")));

        // TypeLib key value
        OLECHAR szLIBID[GUID_STRLEN];

        StringFromGUID2(LIBID_AXVLC, szLIBID, GUID_STRLEN);

        keyClose(keySetDef(keyCreate(hClassKey,TEXT("TypeLib")),
                           szLIBID, sizeof(szLIBID)));

        RegCloseKey(hClassKey);
    }
    return S_OK;
}

STDAPI DllRegisterServer(VOID)
{
    DllUnregisterServer();

    TCHAR DllPath[MAX_PATH];
    DWORD DllPathLen=GetModuleFileName(h_instance, DllPath, MAX_PATH) ;
    if( 0 == DllPathLen )
        return E_UNEXPECTED;
    DllPath[MAX_PATH-1] = '\0';

    HKEY hBaseKey;

    if( ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"),
                                      0, KEY_CREATE_SUB_KEY, &hBaseKey) )
        return SELFREG_E_CLASS;

    RegisterClassID(hBaseKey, CLSID_VLCPlugin, 1, FALSE, DllPath, DllPathLen);
    RegisterClassID(hBaseKey, CLSID_VLCPlugin2, 2, TRUE, DllPath, DllPathLen);

    RegCloseKey(hBaseKey);

    // indicate which component categories we support
    ICatRegister *pcr;
    if( SUCCEEDED(CoCreateInstance(CLSID_StdComponentCategoriesMgr,
            NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr)) ) {
        CATID implCategories[] = {
            CATID_Control,
            CATID_PersistsToPropertyBag,
            CATID_InternetAware,
            CATID_SafeForInitializing,
            CATID_SafeForScripting,
        };

        pcr->RegisterClassImplCategories(CLSID_VLCPlugin,
                sizeof(implCategories)/sizeof(CATID), implCategories);
        pcr->RegisterClassImplCategories(CLSID_VLCPlugin2,
                sizeof(implCategories)/sizeof(CATID), implCategories);
        pcr->Release();
    }

#ifdef BUILD_LOCALSERVER
    // replace .exe by .tlb
    _tcscpy(DllPath+DllPathLen-4, TEXT(".tlb"));
#endif

    // register type lib into the registry
    ITypeLib *typeLib;

    HRESULT result = LoadTypeLibEx(DllPath, REGKIND_REGISTER, &typeLib);
    if( SUCCEEDED(result) )
        typeLib->Release();

    return result;
};

#ifdef BUILD_LOCALSERVER

/*
** easier to debug an application than a DLL on cygwin GDB :)
*/
#include <iostream>

STDAPI_(int) WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
    MSG msg;

    if( FAILED(OleInitialize(NULL)) )
    {
        cerr << "cannot initialize OLE" << endl;
        return 1;
    }

    h_instance = hInst;

    if( FAILED(DllRegisterServer()) )
    {
        cerr << "cannot register Local Server" << endl;
        return 1;
    }

    IUnknown *classProc = NULL;

    if( FAILED(DllGetClassObject(CLSID_VLCPlugin, IID_IUnknown,
                                 (LPVOID *)&classProc)) )
        return 0;

    DWORD dwRegisterClassObject;
    DWORD dwRegisterClassObject2;

    if( FAILED(CoRegisterClassObject(CLSID_VLCPlugin, classProc,
        CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegisterClassObject)) )
        return 0;

    DWORD dwRegisterActiveObject;

    if( FAILED(RegisterActiveObject(classProc, CLSID_VLCPlugin,
                    ACTIVEOBJECT_WEAK, &dwRegisterActiveObject)) )
        return 0;

    if( FAILED(RegisterActiveObject(classProc, CLSID_VLCPlugin2,
                    ACTIVEOBJECT_WEAK, &dwRegisterActiveObject2)) )
        return 0;

    classProc->Release();

    /*
    * Polling messages from event queue
    */
    while( S_FALSE == DllCanUnloadNow() )
    {
        while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
        {
            if( msg.message == WM_QUIT )
                break;  // break out PeekMessage loop

            /*if(TranslateAccelerator(ghwndApp, ghAccel, &msg))
                continue;*/

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if(msg.message == WM_QUIT)
            break;  // break out main loop

        WaitMessage();
    }

    if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject, NULL)) )
        CoRevokeClassObject(dwRegisterClassObject);

    if( SUCCEEDED(RevokeActiveObject(dwRegisterActiveObject2, NULL)) )
        CoRevokeClassObject(dwRegisterClassObject2);

    // Reached on WM_QUIT message
    OleUninitialize();
    return ((int) msg.wParam);
};

#else

STDAPI_(BOOL) DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved )
{
    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
            h_instance = (HINSTANCE)hModule;
            break;

        default:
            break;
    }
    return TRUE;
};

#endif

<|endoftext|>


<commit_before>/*
 * Properties.cpp
 *
 * Copyright 2002, Log4cpp Project. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include "Properties.hh"
#include <cstdlib>
#include "StringUtil.hh"

namespace log4cpp {

    Properties::Properties() {
    }

    Properties::~Properties() {
    }

    void Properties::load(std::istream& in) {
        clear();

        std::string fullLine, command;
        std::string leftSide, rightSide;
        char line[256];
        std::string::size_type length;
        bool partiallyRead(false);	// fix for bug#137, for strings longer than 256 chars

        while (in) {
        	if (in.getline(line, 256) || !in.bad()) {
        		// either string is read fully or only partially (logical but not read/write error)
        		if (partiallyRead)
        			fullLine.append(line);
        		else
        			fullLine = line;
        		partiallyRead = (in.fail() && !in.bad());
        		if (partiallyRead && !in.eof()) {
        			in.clear(in.rdstate() & ~std::ios::failbit);
        			continue; // to get full line
        		}
        	} else {
       			break;
        	}
            /* if the line contains a # then it is a comment
               if we find it anywhere other than the beginning, then we assume
               there is a command on that line, and it we don't find it at all
               we assume there is a command on the line (we test for valid
               command later) if neither is true, we continue with the next line
            */
            length = fullLine.find('#');
            if (length == std::string::npos) {
                command = fullLine;
            } else if (length > 0) {
                command = fullLine.substr(0, length);
            } else {
                continue;
            }

            // check the command and handle it
            length = command.find('=');
            if (length != std::string::npos) {
                leftSide = StringUtil::trim(command.substr(0, length));
                rightSide = StringUtil::trim(command.substr(length + 1, command.size() - length));
                _substituteVariables(rightSide);
            } else {
                continue;
            }

            /* handle the command by determining what object the left side
               refers to and setting the value given on the right
               ASSUMPTIONS:
               1. first object given  on left side is "log4j" or "log4cpp"
               2. all class names on right side are ignored because we
               probably cannot resolve them anyway.
            */

            // strip off the "log4j" or "log4cpp"
            length = leftSide.find('.');
            if (leftSide.substr(0, length) == "log4j" ||
                leftSide.substr(0, length) == "log4cpp")
                leftSide = leftSide.substr(length + 1);

            // add to the map of properties
            insert(value_type(leftSide, rightSide));
        }
    }

    void Properties::save(std::ostream& out) {
        for(const_iterator i = begin(); i != end(); ++i) {
            out << (*i).first << "=" << (*i).second << std::endl;
        }
    }

    int Properties::getInt(const std::string& property, int defaultValue) {
        const_iterator key = find(property);
        return (key == end()) ? defaultValue : std::atoi((*key).second.c_str());
    }

    bool Properties::getBool(const std::string& property, bool defaultValue) {
        const_iterator key = find(property);
        return (key == end()) ? defaultValue : ((*key).second == "true");
    }

    std::string Properties::getString(const std::string& property,
                                      const char* defaultValue) {
        const_iterator key = find(property);
        return (key == end()) ? std::string(defaultValue) : (*key).second;
    }

    void Properties::_substituteVariables(std::string& value) {
        std::string result;

        std::string::size_type left = 0;
        std::string::size_type right = value.find("${", left);
        if (right == std::string::npos) {
            // bail out early for 99% of cases
            return;
        }

        while(true) {
            result += value.substr(left, right - left);
            if (right == std::string::npos) {
                break;
            }

            left = right + 2;
            right = value.find('}', left);
            if (right == std::string::npos) {
                // no close tag, use string literally
                result += value.substr(left - 2);
                break;
            } else {
                const std::string key = value.substr(left, right - left);
                if (key == "${") {
                    result += "${";
                } else {
                    char* value = std::getenv(key.c_str());
                    if (value) {
                        result += value;
                    } else {
                        const_iterator it = find(key);
                        if (it == end()) {
                            // not found assume empty;
                        } else {
                            result += (*it).second;
                        }
                    }
                }
                left = right + 1;
            }

            right = value.find("${", left);
        }

        value = result;
    }
}
<commit_msg>small rename<commit_after>/*
 * Properties.cpp
 *
 * Copyright 2002, Log4cpp Project. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include "Properties.hh"
#include <cstdlib>
#include "StringUtil.hh"

namespace log4cpp {

    Properties::Properties() {
    }

    Properties::~Properties() {
    }

    void Properties::load(std::istream& in) {
        clear();

        std::string fullLine, command;
        std::string leftSide, rightSide;
        char line[256];
        std::string::size_type length;
        bool partiallyRead(false);	// fix for bug#137, for strings longer than 256 chars

        while (in) {
        	if (in.getline(line, 256) || !in.bad()) {
        		// either string is read fully or only partially (logical but not read/write error)
        		if (partiallyRead)
        			fullLine.append(line);
        		else
        			fullLine = line;
        		partiallyRead = (in.fail() && !in.bad());
        		if (partiallyRead && !in.eof()) {
        			in.clear(in.rdstate() & ~std::ios::failbit);
        			continue; // to get full line
        		}
        	} else {
       			break;
        	}
            /* if the line contains a # then it is a comment
               if we find it anywhere other than the beginning, then we assume
               there is a command on that line, and it we don't find it at all
               we assume there is a command on the line (we test for valid
               command later) if neither is true, we continue with the next line
            */
            length = fullLine.find('#');
            if (length == std::string::npos) {
                command = fullLine;
            } else if (length > 0) {
                command = fullLine.substr(0, length);
            } else {
                continue;
            }

            // check the command and handle it
            length = command.find('=');
            if (length != std::string::npos) {
                leftSide = StringUtil::trim(command.substr(0, length));
                rightSide = StringUtil::trim(command.substr(length + 1, command.size() - length));
                _substituteVariables(rightSide);
            } else {
                continue;
            }

            /* handle the command by determining what object the left side
               refers to and setting the value given on the right
               ASSUMPTIONS:
               1. first object given  on left side is "log4j" or "log4cpp"
               2. all class names on right side are ignored because we
               probably cannot resolve them anyway.
            */

            // strip off the "log4j" or "log4cpp"
            length = leftSide.find('.');
            if (leftSide.substr(0, length) == "log4j" ||
                leftSide.substr(0, length) == "log4cpp")
                leftSide = leftSide.substr(length + 1);

            // add to the map of properties
            insert(value_type(leftSide, rightSide));
        }
    }

    void Properties::save(std::ostream& out) {
        for(const_iterator i = begin(); i != end(); ++i) {
            out << (*i).first << "=" << (*i).second << std::endl;
        }
    }

    int Properties::getInt(const std::string& property, int defaultValue) {
        const_iterator key = find(property);
        return (key == end()) ? defaultValue : std::atoi((*key).second.c_str());
    }

    bool Properties::getBool(const std::string& property, bool defaultValue) {
        const_iterator key = find(property);
        return (key == end()) ? defaultValue : ((*key).second == "true");
    }

    std::string Properties::getString(const std::string& property,
                                      const char* defaultValue) {
        const_iterator key = find(property);
        return (key == end()) ? std::string(defaultValue) : (*key).second;
    }

    void Properties::_substituteVariables(std::string& value) {
        std::string result;

        std::string::size_type left = 0;
        std::string::size_type right = value.find("${", left);
        if (right == std::string::npos) {
            // bail out early for 99% of cases
            return;
        }

        while(true) {
            result += value.substr(left, right - left);
            if (right == std::string::npos) {
                break;
            }

            left = right + 2;
            right = value.find('}', left);
            if (right == std::string::npos) {
                // no close tag, use string literally
                result += value.substr(left - 2);
                break;
            } else {
                const std::string key = value.substr(left, right - left);
                if (key == "${") {
                    result += "${";
                } else {
                    char* env_value = std::getenv(key.c_str());
                    if (env_value) {
                        result += env_value;
                    } else {
                        const_iterator it = find(key);
                        if (it == end()) {
                            // not found assume empty;
                        } else {
                            result += (*it).second;
                        }
                    }
                }
                left = right + 1;
            }

            right = value.find("${", left);
        }

        value = result;
    }
}
<|endoftext|>


<commit_before>#include "Rasterizer.h"
#include <limits>   //numerics::max
#include "Utils.h"  //
#include <algorithm> // std::max
Rasterizer::Rasterizer()
  : Renderer() {

}

Rasterizer::Rasterizer(World* world)
  : Renderer(world) {

}

Rasterizer::~Rasterizer() {
}

void Rasterizer::render(const std::string output_path, const uint16_t image_width, const uint16_t image_height) {
  m_pixels = std::vector<RGBColor>(image_height * image_width, BACKGROUND_COLOR);
  m_depth_buffer = std::vector<double>(image_height * image_width, m_camera->get_far_plane());

  for (auto& object : m_world->m_objects) {
    const std::vector<Triangle3D> triangles = object->triangulate();
    for (auto& triangle_world : triangles) {
      const Triangle2D triangle_projected = this->project(triangle_world);
      const Triangle2D triangle_raster = this->rasterize(triangle_world);
      const BoundingBox2D bbox_raster = triangle_raster.bbox();
      for (int32_t pixel_raster_x = bbox_raster.min.x; pixel_raster_x <= bbox_raster.max.x; ++pixel_raster_x) {
        for (int32_t pixel_raster_y = bbox_raster.min.y; pixel_raster_y <= bbox_raster.max.y; ++pixel_raster_y) {
          const Point2D pixel_raster = { (double) pixel_raster_x, (double) pixel_raster_y };
          if (triangle_raster.contains(pixel_raster)) {
            const Point2D pixel_projected = this->unproject(pixel_raster);
            const double depth = getDepth(triangle_world, triangle_projected, pixel_projected);
            const Point3D pixel_view = m_camera->projectTransformInv(pixel_projected, depth);
            const Point3D pixel_world = pixel_view;
            // TODO: const Point3D pixel_world = m_camera->viewTransformInv(pixel_view);
            if (m_camera->insideFrustrum(pixel_raster, depth)) {
              const uint32_t i = pixel_raster_y * image_width + pixel_raster_x;
              if (depth < m_depth_buffer[i]) {
                m_depth_buffer[i] = depth;
                m_pixels[i] = shade(*object, triangle_world, pixel_world);
              }
            }
          }
        }
      }
    }
  }

  exportDepthBuffer(m_depth_buffer, "depth.bmp", image_width, image_height);
  exportImage(m_pixels, output_path, image_width, image_height);
}

const double Rasterizer::getDepth(const Triangle3D& triangle_world, const Triangle2D& triangle_screen, const Point2D& pixel_screen) const {
  const Triangle3D triangle_camera = Triangle3D(
    m_camera->viewTransform(triangle_world.v1),
    m_camera->viewTransform(triangle_world.v2),
    m_camera->viewTransform(triangle_world.v3)
  );

  // Calculate barycentric coords in camera space
  double u, v, w;
  triangle_screen.calculateBarycentricCoords(u, v, w, pixel_screen);
  // Interpolate Z in 3D using inverse function and barycentric coordinates in 2D
  const float depth = 1 / ((1 / triangle_camera.v1.z) * u + (1 / triangle_camera.v2.z) * v + (1 / triangle_camera.v3.z) * w);
  return depth;

}

const Point2D Rasterizer::rasterize(const Point3D& point_world) const {
  const Point3D point_camera = m_camera->viewTransform(point_world);
  const Point2D point_projected = m_camera->projectTransform(point_camera);
  const Point2D point_ndc = m_camera->ndcTransform(point_projected);
  const Point2D point_raster = m_camera->viewportTransform(point_ndc);
  return point_raster;
}

const Triangle2D Rasterizer::rasterize(const Triangle3D& triangle_world) const {
  return Triangle2D(
    rasterize(triangle_world.v1),
    rasterize(triangle_world.v2),
    rasterize(triangle_world.v3)
  );
}

const Triangle2D Rasterizer::project(const Triangle3D& triangle_world) const {
  return Triangle2D(
    project(triangle_world.v1),
    project(triangle_world.v2),
    project(triangle_world.v3)
  );
}

const Point2D Rasterizer::project(const Point3D& point_world) const {
  const Point3D point_camera = m_camera->viewTransform(point_world);
  const Point2D point_projected = m_camera->projectTransform(point_camera);
  return point_projected;
}

const Point2D Rasterizer::unproject(const Point2D& point_raster) const {
  const Point2D point_ndc = m_camera->viewportTransformInv(point_raster);
  const Point2D point_projected = m_camera->ndcTransformInv(point_ndc);
  return point_projected;
}

const RGBColor Rasterizer::shade(const GeometryObject& object, const Triangle3D& triangle, const Point3D point_in_triangle) const {
#ifdef _PHONG
  return phongShading(object.m_material, object.m_color, triangle, point_in_triangle);
#endif // _PHONG

#ifdef _BLINN_PHONG
  return blinnPhongShading(object.m_material, object.m_color, triangle, point_in_triangle);
#endif // _BLINN-PHONG
}

const RGBColor Rasterizer::phongShading(const Material& material, const RGBColor& base_color, const Triangle3D& triangle, const Point3D& point_in_triangle) const {
  const RGBColor ambient = AMBIENT_COLOR * k_a;

  RGBColor diffuse, specular;
  for (auto& light : m_world->m_lights) {
    const Vector3D L = -(light->getDirectionToPoint(point_in_triangle));
    const Vector3D N = triangle.normal;
    const Vector3D R = 2 * (N * L) * N - L;
    const Vector3D V = -(m_world->m_camera->viewDirection(point_in_triangle));

    diffuse += light->getColor() * material.k_d * std::max((L * N), 0.0);
    specular += light->getColor() *  material.k_s * pow(std::max((R * V), 0.0), material.k_shininess);
  }
  const RGBColor phong_result = (ambient + diffuse + specular) * base_color;
  return phong_result;
}

const RGBColor Rasterizer::blinnPhongShading(const Material& material, const RGBColor& base_color, const Triangle3D& triangle, const Point3D& point_in_triangle) const {
  const RGBColor ambient = AMBIENT_COLOR * k_a;

  RGBColor diffuse, specular;
  for (auto& light : m_world->m_lights) {
    const Vector3D L = -(light->getDirectionToPoint(point_in_triangle));
    const Vector3D N = triangle.normal;
    const Vector3D V = -(m_world->m_camera->viewDirection(point_in_triangle));
    // Halfway calculation: Can be moved outside to increase performance
    Vector3D H = V + L;
    H.normalize();
    float a = (H * V);
    diffuse += light->getColor() * material.k_d * std::max((L * N), 0.0);
    specular += light->getColor() * material.k_s  * pow(std::max((H * V), 0.0), material.k_shininess);
  }
  const RGBColor phong_result = (ambient + diffuse + specular) * base_color;
  return phong_result;
}

void Rasterizer::exportDepthBuffer(const std::vector<double>& depth_buffer, const std::string output_path, const uint16_t image_width, const uint16_t image_height) const {
  std::vector<RGBColor> depth_buffer_grey(image_height*image_width, RGBColor(1.0));
  for (int i = 0; i < depth_buffer.size(); ++i) {
    const double depth = depth_buffer[i];
    if (depth != m_camera->get_far_plane()) {
      // Convert depth in the range [near, far] to [0,1]
      const double slope = 1.0 / (m_camera->get_far_plane() - m_camera->get_near_plane());
      const double depth_normalized = slope * (depth - m_camera->get_near_plane());
      depth_buffer_grey[i] = RGBColor(depth_normalized);
    }
  }
  exportImage(depth_buffer_grey, output_path, image_width, image_height);
}<commit_msg>Added transformation from view to world<commit_after>#include "Rasterizer.h"
#include <limits>   //numerics::max
#include "Utils.h"  //
#include <algorithm> // std::max
Rasterizer::Rasterizer()
  : Renderer() {

}

Rasterizer::Rasterizer(World* world)
  : Renderer(world) {

}

Rasterizer::~Rasterizer() {
}

void Rasterizer::render(const std::string output_path, const uint16_t image_width, const uint16_t image_height) {
  m_pixels = std::vector<RGBColor>(image_height * image_width, BACKGROUND_COLOR);
  m_depth_buffer = std::vector<double>(image_height * image_width, m_camera->get_far_plane());

  for (auto& object : m_world->m_objects) {
    const std::vector<Triangle3D> triangles = object->triangulate();
    for (auto& triangle_world : triangles) {
      const Triangle2D triangle_projected = this->project(triangle_world);
      const Triangle2D triangle_raster = this->rasterize(triangle_world);
      const BoundingBox2D bbox_raster = triangle_raster.bbox();
      for (int32_t pixel_raster_x = bbox_raster.min.x; pixel_raster_x <= bbox_raster.max.x; ++pixel_raster_x) {
        for (int32_t pixel_raster_y = bbox_raster.min.y; pixel_raster_y <= bbox_raster.max.y; ++pixel_raster_y) {
          const Point2D pixel_raster = { (double) pixel_raster_x, (double) pixel_raster_y };
          if (triangle_raster.contains(pixel_raster)) {
            const Point2D pixel_projected = this->unproject(pixel_raster);
            const double depth = getDepth(triangle_world, triangle_projected, pixel_projected);
            const Point3D pixel_view = m_camera->projectTransformInv(pixel_projected, depth);
            const Point3D pixel_world = m_camera->viewTransformInv(pixel_view);
            if (m_camera->insideFrustrum(pixel_raster, depth)) {
              const uint32_t i = pixel_raster_y * image_width + pixel_raster_x;
              if (depth < m_depth_buffer[i]) {
                m_depth_buffer[i] = depth;
                m_pixels[i] = shade(*object, triangle_world, pixel_world);
              }
            }
          }
        }
      }
    }
  }

  exportDepthBuffer(m_depth_buffer, "depth.bmp", image_width, image_height);
  exportImage(m_pixels, output_path, image_width, image_height);
}

const double Rasterizer::getDepth(const Triangle3D& triangle_world, const Triangle2D& triangle_screen, const Point2D& pixel_screen) const {
  const Triangle3D triangle_camera = Triangle3D(
    m_camera->viewTransform(triangle_world.v1),
    m_camera->viewTransform(triangle_world.v2),
    m_camera->viewTransform(triangle_world.v3)
  );

  // Calculate barycentric coords in camera space
  double u, v, w;
  triangle_screen.calculateBarycentricCoords(u, v, w, pixel_screen);
  // Interpolate Z in 3D using inverse function and barycentric coordinates in 2D
  const float depth = 1 / ((1 / triangle_camera.v1.z) * u + (1 / triangle_camera.v2.z) * v + (1 / triangle_camera.v3.z) * w);
  return depth;

}

const Point2D Rasterizer::rasterize(const Point3D& point_world) const {
  const Point3D point_camera = m_camera->viewTransform(point_world);
  const Point2D point_projected = m_camera->projectTransform(point_camera);
  const Point2D point_ndc = m_camera->ndcTransform(point_projected);
  const Point2D point_raster = m_camera->viewportTransform(point_ndc);
  return point_raster;
}

const Triangle2D Rasterizer::rasterize(const Triangle3D& triangle_world) const {
  return Triangle2D(
    rasterize(triangle_world.v1),
    rasterize(triangle_world.v2),
    rasterize(triangle_world.v3)
  );
}

const Triangle2D Rasterizer::project(const Triangle3D& triangle_world) const {
  return Triangle2D(
    project(triangle_world.v1),
    project(triangle_world.v2),
    project(triangle_world.v3)
  );
}

const Point2D Rasterizer::project(const Point3D& point_world) const {
  const Point3D point_camera = m_camera->viewTransform(point_world);
  const Point2D point_projected = m_camera->projectTransform(point_camera);
  return point_projected;
}

const Point2D Rasterizer::unproject(const Point2D& point_raster) const {
  const Point2D point_ndc = m_camera->viewportTransformInv(point_raster);
  const Point2D point_projected = m_camera->ndcTransformInv(point_ndc);
  return point_projected;
}

const RGBColor Rasterizer::shade(const GeometryObject& object, const Triangle3D& triangle, const Point3D point_in_triangle) const {
#ifdef _PHONG
  return phongShading(object.m_material, object.m_color, triangle, point_in_triangle);
#endif // _PHONG

#ifdef _BLINN_PHONG
  return blinnPhongShading(object.m_material, object.m_color, triangle, point_in_triangle);
#endif // _BLINN-PHONG
}

const RGBColor Rasterizer::phongShading(const Material& material, const RGBColor& base_color, const Triangle3D& triangle, const Point3D& point_in_triangle) const {
  const RGBColor ambient = AMBIENT_COLOR * k_a;

  RGBColor diffuse, specular;
  for (auto& light : m_world->m_lights) {
    const Vector3D L = -(light->getDirectionToPoint(point_in_triangle));
    const Vector3D N = triangle.normal;
    const Vector3D R = 2 * (N * L) * N - L;
    const Vector3D V = -(m_world->m_camera->viewDirection(point_in_triangle));

    diffuse += light->getColor() * material.k_d * std::max((L * N), 0.0);
    specular += light->getColor() *  material.k_s * pow(std::max((R * V), 0.0), material.k_shininess);
  }
  const RGBColor phong_result = (ambient + diffuse + specular) * base_color;
  return phong_result;
}

const RGBColor Rasterizer::blinnPhongShading(const Material& material, const RGBColor& base_color, const Triangle3D& triangle, const Point3D& point_in_triangle) const {
  const RGBColor ambient = AMBIENT_COLOR * k_a;

  RGBColor diffuse, specular;
  for (auto& light : m_world->m_lights) {
    const Vector3D L = -(light->getDirectionToPoint(point_in_triangle));
    const Vector3D N = triangle.normal;
    const Vector3D V = -(m_world->m_camera->viewDirection(point_in_triangle));
    // Halfway calculation: Can be moved outside to increase performance
    Vector3D H = V + L;
    H.normalize();
    float a = (H * V);
    diffuse += light->getColor() * material.k_d * std::max((L * N), 0.0);
    specular += light->getColor() * material.k_s  * pow(std::max((H * V), 0.0), material.k_shininess);
  }
  const RGBColor phong_result = (ambient + diffuse + specular) * base_color;
  return phong_result;
}

void Rasterizer::exportDepthBuffer(const std::vector<double>& depth_buffer, const std::string output_path, const uint16_t image_width, const uint16_t image_height) const {
  std::vector<RGBColor> depth_buffer_grey(image_height*image_width, RGBColor(1.0));
  for (int i = 0; i < depth_buffer.size(); ++i) {
    const double depth = depth_buffer[i];
    if (depth != m_camera->get_far_plane()) {
      // Convert depth in the range [near, far] to [0,1]
      const double slope = 1.0 / (m_camera->get_far_plane() - m_camera->get_near_plane());
      const double depth_normalized = slope * (depth - m_camera->get_near_plane());
      depth_buffer_grey[i] = RGBColor(depth_normalized);
    }
  }
  exportImage(depth_buffer_grey, output_path, image_width, image_height);
}<|endoftext|>


<commit_before>#include "Common.h"
#include "SSEChannel.h"
#include "SSEClient.h"
#include "SSEClientHandler.h"
#include "SSEEvent.h"
#include "SSEConfig.h"
#include "HTTPRequest.h"
#include "HTTPResponse.h"
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

using namespace std;
extern int stop;

/**
  Constructor.
  @param conf Pointer to SSEConfig instance holding our configuration.
  @param id Unique identifier for this channel.
*/
SSEChannel::SSEChannel(ChannelConfig conf, string id) {
  _config = conf;
  _config.id = id;

  _efd = epoll_create1(0);
  LOG_IF(FATAL, _efd == -1) << "epoll_create1 failed.";

  // Initialize counters.
  _stats.num_clients            = 0;
  _stats.num_connects           = 0;
  _stats.num_disconnects        = 0;
  _stats.num_errors             = 0;
  _stats.num_cached_events      = 0;
  _stats.num_broadcasted_events = 0;
  _stats.cache_size             = _config.cacheLength;

  LOG(INFO) << "Initializing channel " << _config.id;
  LOG(INFO) << "Cache Adapter: " << _config.cacheAdapter;
  LOG(INFO) << "Cache length: " << _config.cacheLength;
  LOG(INFO) << "Threads per channel: " << _config.server->GetValue("server.threadsPerChannel");

  _allow_all_origins = (_config.allowedOrigins.size() < 1) ? true : false;

  BOOST_FOREACH(const std::string& origin, _config.allowedOrigins) {
    DLOG(INFO) << "Allowed origin: " << origin;
  }

  // Internet Explorer has a problem receiving data when using XDomainRequest before it has received 2KB of data.
  // The polyfills that account for this send a query parameter, evs_preamble to inform the server about this so it can respond with some initial data.
  // Initialize a buffer containing our response for this case.
  _evs_preamble_data[0] = ':';
  for (int i = 1; i <= 2048; i++) { _evs_preamble_data[i] = '.'; }
  _evs_preamble_data[2049] = '\n';
  _evs_preamble_data[2050] = '\n';
  _evs_preamble_data[2051] = '\0';

  InitializeCache();
  InitializeThreads();
}

/**
  Destructor.
*/
SSEChannel::~SSEChannel() {
  DLOG(INFO) << "SSEChannel destructor called.";
  CleanupThreads();
}

/*
  Initialize the configured cacheadapter for this channel
*/
void SSEChannel::InitializeCache() {
  const string adapter = _config.cacheAdapter;
  if (adapter == "redis") {
    _cache_adapter = new Redis(_config.id, _config);
  } else if (adapter == "memory") {
    _cache_adapter = new Memory(_config);
  } else if (adapter == "leveldb") {
    _cache_adapter = new LevelDB(_config);
  }

  if (_cache_adapter) {
    _stats.num_cached_events = _cache_adapter->GetSizeOfCachedEvents();
  }
}

/**
  Initialize client handler threads and also the thread that
  pings all connected clients on _config.red interval.
*/
void SSEChannel::InitializeThreads() {
  int i;

  _cleanupthread = boost::thread(boost::bind(&SSEChannel::CleanupMain, this));

  for (i = 0; i < _config.server->GetValueInt("server.threadsPerChannel"); i++) {
    _clientpool.push_back(ClientHandlerPtr(new SSEClientHandler(i)));
  }

  curthread = _clientpool.begin();
  _pingthread = boost::thread(boost::bind(&SSEChannel::Ping, this));
}

/**
  Stop and free up all running threads.
  Called by destructor.
*/
void SSEChannel::CleanupThreads() {
  pthread_cancel(_pingthread.native_handle());
  pthread_cancel(_cleanupthread.native_handle());
}

/**
  Return the id of this channel.
*/
string SSEChannel::GetId() {
  return _config.id;
}

/**
 Set correct CORS headers.
 @param req Request object.
 @param res Response object.
*/
void SSEChannel::SetCorsHeaders(HTTPRequest* req, HTTPResponse& res) {
  // Set allowed headers for the EventSource IE polyfill
  res.SetHeader("Access-Control-Allow-Headers", "Accept, Cache-Control, X-Requested-With, Last-Event-ID");

  if (_allow_all_origins) {
    DLOG(INFO) << "All origins allowed.";
    res.SetHeader("Access-Control-Allow-Origin", "*");
    return;
  }

  const string& originHeader = req->GetHeader("Origin");

  // If Origin header is not set in the request don't set any CORS headers.
  if (originHeader.empty()) {
    DLOG(INFO) << "No Origin header in request, not setting cors headers.";
    return;
  }

  // If Origin matches one of the origins in the allowedOrigins array use that in the CORS header.
  BOOST_FOREACH(const std::string& origin, _config.allowedOrigins) {
    if (originHeader.compare(0, origin.size(), origin) == 0) {
      res.SetHeader("Access-Control-Allow-Origin", origin);
      DLOG(INFO) << "Referer matches origin " << origin;
      return;
    }
  }
}

/**
  Adds a client to one of the client handlers assigned to the channel.
  Clients is distributed evenly across the client handler threads.
  @param client SSEClient pointer.
*/
void SSEChannel::AddClient(SSEClient* client, HTTPRequest* req) {
  HTTPResponse res;
  struct epoll_event ev;
  int ret;

  DLOG(INFO) << "Adding client to channel " << GetId();

  // Send CORS headers.
  SetCorsHeaders(req, res);

   // Reply with CORS headers when we get a OPTIONS request.
  if (req->GetMethod().compare("OPTIONS") == 0) {
    client->Send(res.Get());
    client->Destroy();
    return;
  }

  // Disallow every other method than GET.
  if (req->GetMethod().compare("GET") != 0) {
    DLOG(INFO) << "Method: " << req->GetMethod();
    res.SetStatus(405, "Method Not Allowed");
    client->Send(res.Get());
    client->Destroy();
    return;
  }

  string lastEventId = req->GetHeader("Last-Event-ID");
  if (lastEventId.empty()) lastEventId = req->GetQueryString("evs_last_event_id");
  if (lastEventId.empty()) lastEventId = req->GetQueryString("lastEventId");

  // Send initial response headers, etc.
  res.SetHeader("Content-Type", "text/event-stream");
  res.SetHeader("Cache-Control", "no-cache");
  res.SetHeader("Connection", "close");
  res.SetBody(":ok\n\n");

  // Send preamble if polyfill require it.
  if (!req->GetQueryString("evs_preamble").empty()) {
    res.AppendBody(_evs_preamble_data);
  }

  client->Send(res.Get());

  // Apply filters.
  if (!req->GetQueryString("filterid").empty()) client->Subscribe(req->GetQueryString("filterid"), SUBSCRIPTION_ID);
  if (!req->GetQueryString("filterevent").empty()) client->Subscribe(req->GetQueryString("filterevent"), SUBSCRIPTION_EVENT_TYPE);

  // Send event history if requested.
  if (!lastEventId.empty()) {
    SendEventsSince(client, lastEventId);
  } else if (!req->GetQueryString("getcache").empty()) {
    SendCache(client);
  }

  client->DeleteHttpReq();

  ev.events   = EPOLLET | EPOLLOUT | EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
  ev.data.ptr = client;
  ret = epoll_ctl(_efd, EPOLL_CTL_ADD, client->Getfd(), &ev);

  if (ret == -1) {
    DLOG(ERROR) << "Failed to add client " << client->GetIP() << " to epoll event list.";
    client->Destroy();
    return;
  }

  INC_LONG(_stats.num_connects);

  // Add client to handler thread in a round-robin fashion.
  (*curthread)->AddClient(client);
  curthread++;

  if (curthread == _clientpool.end()) curthread = _clientpool.begin();
}

/**
  Broadcasts string to all connected clients.
  @param data String to broadcast.
*/
void SSEChannel::Broadcast(const string& data) {
  ClientHandlerList::iterator it;

  for (it = _clientpool.begin(); it != _clientpool.end(); it++) {
    (*it)->Broadcast(data);
  }
}

/**
  Broadcasts SSEvent to all connected clients.
  @param event Event to broadcast.
*/
void SSEChannel::BroadcastEvent(SSEEvent& event) {
  Broadcast(event.get());
  INC_LONG(_stats.num_broadcasted_events);

  // Add event to cache if it contains a id field.
  if (!event.getid().empty()) {
    CacheEvent(event);
  }
}

/**
  Add event to cache.
  @param event Event to cache.
*/
void SSEChannel::CacheEvent(SSEEvent& event) {
  if (_cache_adapter) {
    _cache_adapter->CacheEvent(event);
    _stats.num_cached_events = _cache_adapter->GetSizeOfCachedEvents();
  }
}

/**
  Send all events since a given event id to client.
  @param lastId Send all events since this id.
*/
void SSEChannel::SendEventsSince(SSEClient* client, string lastId) {
  deque<string>::const_iterator it;
  deque<string> events = _cache_adapter->GetEventsSinceId(lastId);

  BOOST_FOREACH(const string& event, events) {
    client->Send(event, SND_NO_FLUSH);
  }
}

/**
  Send all cached events to client.
  @param client SSEClient.
*/
void SSEChannel::SendCache(SSEClient* client) {
 deque<string>::const_iterator it;
 deque<string> events = _cache_adapter->GetAllEvents();

  BOOST_FOREACH(const string& event, events) {
    client->Send(event, SND_NO_FLUSH);
  }
}

/**
 Handle client disconnects and errors.
*/
void SSEChannel::CleanupMain() {
  boost::shared_ptr<struct epoll_event[]> t_events(new struct epoll_event[1024]);

  while(!stop) {
    int n = epoll_wait(_efd, t_events.get(), 1024, -1);

    for (int i = 0; i < n; i++) {
      SSEClient* client;
      client = static_cast<SSEClient*>(t_events[i].data.ptr);

      if (t_events[i].events & EPOLLIN) {
        char buf[512];
        int rcv_len = client->Read(buf, 512);
        if (rcv_len <= 0) {
          client->MarkAsDead();
          INC_LONG(_stats.num_disconnects);
        }
      } else if ((t_events[i].events & EPOLLHUP)  || (t_events[i].events & EPOLLRDHUP)) {
        DLOG(INFO) << "Channel " << _config.id << ": Client disconnected.";
        client->MarkAsDead();
        INC_LONG(_stats.num_disconnects);
      } else if (t_events[i].events & EPOLLERR) {
        // If an error occurs on a client socket, just drop the connection.
        DLOG(INFO) << "Channel " << _config.id << ": Error on client socket: " << strerror(errno);
        client->MarkAsDead();
        INC_LONG(_stats.num_errors);
      } else if (t_events[i].events & EPOLLOUT) {
        // Send data present in send buffer,
        DLOG(INFO) << client->GetIP() << ": EPOLLOUT, flushing send buffer.";
        client->Flush();
      }
    }
  }
}

/**
  Sends a ping to all clients connected to this channel.
*/
void SSEChannel::Ping() {
  while(!stop) {
    Broadcast(":\n\n");
    sleep(_config.server->GetValueInt("server.pingInterval"));
  }
}

/**
  Returns number of clients connected to this channel.
*/
ulong SSEChannel::GetNumClients() {
  ClientHandlerList::iterator it;
  ulong numclients = 0;

  for (it = _clientpool.begin(); it != _clientpool.end(); it++) {
    numclients += (*it)->GetNumClients();
  }

  return numclients;
}

/**
 Fetch various statistics for the channel.
 @param stats Pointer to SSEChannelStats struct which is to be filled with the statistics.
**/
const SSEChannelStats& SSEChannel::GetStats() {
  _stats.num_clients = GetNumClients();
  return _stats;
}

/**
  Returns the ChannelConfig.
**/
const ChannelConfig& SSEChannel::GetConfig() {
  return _config;
}
<commit_msg>Send ping as en event, and not a "comment"<commit_after>#include "Common.h"
#include "SSEChannel.h"
#include "SSEClient.h"
#include "SSEClientHandler.h"
#include "SSEEvent.h"
#include "SSEConfig.h"
#include "HTTPRequest.h"
#include "HTTPResponse.h"
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

using namespace std;
extern int stop;

/**
  Constructor.
  @param conf Pointer to SSEConfig instance holding our configuration.
  @param id Unique identifier for this channel.
*/
SSEChannel::SSEChannel(ChannelConfig conf, string id) {
  _config = conf;
  _config.id = id;

  _efd = epoll_create1(0);
  LOG_IF(FATAL, _efd == -1) << "epoll_create1 failed.";

  // Initialize counters.
  _stats.num_clients            = 0;
  _stats.num_connects           = 0;
  _stats.num_disconnects        = 0;
  _stats.num_errors             = 0;
  _stats.num_cached_events      = 0;
  _stats.num_broadcasted_events = 0;
  _stats.cache_size             = _config.cacheLength;

  LOG(INFO) << "Initializing channel " << _config.id;
  LOG(INFO) << "Cache Adapter: " << _config.cacheAdapter;
  LOG(INFO) << "Cache length: " << _config.cacheLength;
  LOG(INFO) << "Threads per channel: " << _config.server->GetValue("server.threadsPerChannel");

  _allow_all_origins = (_config.allowedOrigins.size() < 1) ? true : false;

  BOOST_FOREACH(const std::string& origin, _config.allowedOrigins) {
    DLOG(INFO) << "Allowed origin: " << origin;
  }

  // Internet Explorer has a problem receiving data when using XDomainRequest before it has received 2KB of data.
  // The polyfills that account for this send a query parameter, evs_preamble to inform the server about this so it can respond with some initial data.
  // Initialize a buffer containing our response for this case.
  _evs_preamble_data[0] = ':';
  for (int i = 1; i <= 2048; i++) { _evs_preamble_data[i] = '.'; }
  _evs_preamble_data[2049] = '\n';
  _evs_preamble_data[2050] = '\n';
  _evs_preamble_data[2051] = '\0';

  InitializeCache();
  InitializeThreads();
}

/**
  Destructor.
*/
SSEChannel::~SSEChannel() {
  DLOG(INFO) << "SSEChannel destructor called.";
  CleanupThreads();
}

/*
  Initialize the configured cacheadapter for this channel
*/
void SSEChannel::InitializeCache() {
  const string adapter = _config.cacheAdapter;
  if (adapter == "redis") {
    _cache_adapter = new Redis(_config.id, _config);
  } else if (adapter == "memory") {
    _cache_adapter = new Memory(_config);
  } else if (adapter == "leveldb") {
    _cache_adapter = new LevelDB(_config);
  }

  if (_cache_adapter) {
    _stats.num_cached_events = _cache_adapter->GetSizeOfCachedEvents();
  }
}

/**
  Initialize client handler threads and also the thread that
  pings all connected clients on _config.red interval.
*/
void SSEChannel::InitializeThreads() {
  int i;

  _cleanupthread = boost::thread(boost::bind(&SSEChannel::CleanupMain, this));

  for (i = 0; i < _config.server->GetValueInt("server.threadsPerChannel"); i++) {
    _clientpool.push_back(ClientHandlerPtr(new SSEClientHandler(i)));
  }

  curthread = _clientpool.begin();
  _pingthread = boost::thread(boost::bind(&SSEChannel::Ping, this));
}

/**
  Stop and free up all running threads.
  Called by destructor.
*/
void SSEChannel::CleanupThreads() {
  pthread_cancel(_pingthread.native_handle());
  pthread_cancel(_cleanupthread.native_handle());
}

/**
  Return the id of this channel.
*/
string SSEChannel::GetId() {
  return _config.id;
}

/**
 Set correct CORS headers.
 @param req Request object.
 @param res Response object.
*/
void SSEChannel::SetCorsHeaders(HTTPRequest* req, HTTPResponse& res) {
  // Set allowed headers for the EventSource IE polyfill
  res.SetHeader("Access-Control-Allow-Headers", "Accept, Cache-Control, X-Requested-With, Last-Event-ID");

  if (_allow_all_origins) {
    DLOG(INFO) << "All origins allowed.";
    res.SetHeader("Access-Control-Allow-Origin", "*");
    return;
  }

  const string& originHeader = req->GetHeader("Origin");

  // If Origin header is not set in the request don't set any CORS headers.
  if (originHeader.empty()) {
    DLOG(INFO) << "No Origin header in request, not setting cors headers.";
    return;
  }

  // If Origin matches one of the origins in the allowedOrigins array use that in the CORS header.
  BOOST_FOREACH(const std::string& origin, _config.allowedOrigins) {
    if (originHeader.compare(0, origin.size(), origin) == 0) {
      res.SetHeader("Access-Control-Allow-Origin", origin);
      DLOG(INFO) << "Referer matches origin " << origin;
      return;
    }
  }
}

/**
  Adds a client to one of the client handlers assigned to the channel.
  Clients is distributed evenly across the client handler threads.
  @param client SSEClient pointer.
*/
void SSEChannel::AddClient(SSEClient* client, HTTPRequest* req) {
  HTTPResponse res;
  struct epoll_event ev;
  int ret;

  DLOG(INFO) << "Adding client to channel " << GetId();

  // Send CORS headers.
  SetCorsHeaders(req, res);

   // Reply with CORS headers when we get a OPTIONS request.
  if (req->GetMethod().compare("OPTIONS") == 0) {
    client->Send(res.Get());
    client->Destroy();
    return;
  }

  // Disallow every other method than GET.
  if (req->GetMethod().compare("GET") != 0) {
    DLOG(INFO) << "Method: " << req->GetMethod();
    res.SetStatus(405, "Method Not Allowed");
    client->Send(res.Get());
    client->Destroy();
    return;
  }

  string lastEventId = req->GetHeader("Last-Event-ID");
  if (lastEventId.empty()) lastEventId = req->GetQueryString("evs_last_event_id");
  if (lastEventId.empty()) lastEventId = req->GetQueryString("lastEventId");

  // Send initial response headers, etc.
  res.SetHeader("Content-Type", "text/event-stream");
  res.SetHeader("Cache-Control", "no-cache");
  res.SetHeader("Connection", "close");
  res.SetBody(":ok\n\n");

  // Send preamble if polyfill require it.
  if (!req->GetQueryString("evs_preamble").empty()) {
    res.AppendBody(_evs_preamble_data);
  }

  client->Send(res.Get());

  // Apply filters.
  if (!req->GetQueryString("filterid").empty()) client->Subscribe(req->GetQueryString("filterid"), SUBSCRIPTION_ID);
  if (!req->GetQueryString("filterevent").empty()) client->Subscribe(req->GetQueryString("filterevent"), SUBSCRIPTION_EVENT_TYPE);

  // Send event history if requested.
  if (!lastEventId.empty()) {
    SendEventsSince(client, lastEventId);
  } else if (!req->GetQueryString("getcache").empty()) {
    SendCache(client);
  }

  client->DeleteHttpReq();

  ev.events   = EPOLLET | EPOLLOUT | EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
  ev.data.ptr = client;
  ret = epoll_ctl(_efd, EPOLL_CTL_ADD, client->Getfd(), &ev);

  if (ret == -1) {
    DLOG(ERROR) << "Failed to add client " << client->GetIP() << " to epoll event list.";
    client->Destroy();
    return;
  }

  INC_LONG(_stats.num_connects);

  // Add client to handler thread in a round-robin fashion.
  (*curthread)->AddClient(client);
  curthread++;

  if (curthread == _clientpool.end()) curthread = _clientpool.begin();
}

/**
  Broadcasts string to all connected clients.
  @param data String to broadcast.
*/
void SSEChannel::Broadcast(const string& data) {
  ClientHandlerList::iterator it;

  for (it = _clientpool.begin(); it != _clientpool.end(); it++) {
    (*it)->Broadcast(data);
  }
}

/**
  Broadcasts SSEvent to all connected clients.
  @param event Event to broadcast.
*/
void SSEChannel::BroadcastEvent(SSEEvent& event) {
  Broadcast(event.get());
  INC_LONG(_stats.num_broadcasted_events);

  // Add event to cache if it contains a id field.
  if (!event.getid().empty()) {
    CacheEvent(event);
  }
}

/**
  Add event to cache.
  @param event Event to cache.
*/
void SSEChannel::CacheEvent(SSEEvent& event) {
  if (_cache_adapter) {
    _cache_adapter->CacheEvent(event);
    _stats.num_cached_events = _cache_adapter->GetSizeOfCachedEvents();
  }
}

/**
  Send all events since a given event id to client.
  @param lastId Send all events since this id.
*/
void SSEChannel::SendEventsSince(SSEClient* client, string lastId) {
  deque<string>::const_iterator it;
  deque<string> events = _cache_adapter->GetEventsSinceId(lastId);

  BOOST_FOREACH(const string& event, events) {
    client->Send(event, SND_NO_FLUSH);
  }
}

/**
  Send all cached events to client.
  @param client SSEClient.
*/
void SSEChannel::SendCache(SSEClient* client) {
 deque<string>::const_iterator it;
 deque<string> events = _cache_adapter->GetAllEvents();

  BOOST_FOREACH(const string& event, events) {
    client->Send(event, SND_NO_FLUSH);
  }
}

/**
 Handle client disconnects and errors.
*/
void SSEChannel::CleanupMain() {
  boost::shared_ptr<struct epoll_event[]> t_events(new struct epoll_event[1024]);

  while(!stop) {
    int n = epoll_wait(_efd, t_events.get(), 1024, -1);

    for (int i = 0; i < n; i++) {
      SSEClient* client;
      client = static_cast<SSEClient*>(t_events[i].data.ptr);

      if (t_events[i].events & EPOLLIN) {
        char buf[512];
        int rcv_len = client->Read(buf, 512);
        if (rcv_len <= 0) {
          client->MarkAsDead();
          INC_LONG(_stats.num_disconnects);
        }
      } else if ((t_events[i].events & EPOLLHUP)  || (t_events[i].events & EPOLLRDHUP)) {
        DLOG(INFO) << "Channel " << _config.id << ": Client disconnected.";
        client->MarkAsDead();
        INC_LONG(_stats.num_disconnects);
      } else if (t_events[i].events & EPOLLERR) {
        // If an error occurs on a client socket, just drop the connection.
        DLOG(INFO) << "Channel " << _config.id << ": Error on client socket: " << strerror(errno);
        client->MarkAsDead();
        INC_LONG(_stats.num_errors);
      } else if (t_events[i].events & EPOLLOUT) {
        // Send data present in send buffer,
        DLOG(INFO) << client->GetIP() << ": EPOLLOUT, flushing send buffer.";
        client->Flush();
      }
    }
  }
}

/**
  Sends a ping to all clients connected to this channel.
*/
void SSEChannel::Ping() {
  while(!stop) {
    Broadcast("event:ping\n\n");
    sleep(_config.server->GetValueInt("server.pingInterval"));
  }
}

/**
  Returns number of clients connected to this channel.
*/
ulong SSEChannel::GetNumClients() {
  ClientHandlerList::iterator it;
  ulong numclients = 0;

  for (it = _clientpool.begin(); it != _clientpool.end(); it++) {
    numclients += (*it)->GetNumClients();
  }

  return numclients;
}

/**
 Fetch various statistics for the channel.
 @param stats Pointer to SSEChannelStats struct which is to be filled with the statistics.
**/
const SSEChannelStats& SSEChannel::GetStats() {
  _stats.num_clients = GetNumClients();
  return _stats;
}

/**
  Returns the ChannelConfig.
**/
const ChannelConfig& SSEChannel::GetConfig() {
  return _config;
}
<|endoftext|>


<commit_before>/*******************************************************************************
GPU OPTIMIZED MONTE CARLO (GOMC) 2.51
Copyright (C) 2018  GOMC Group
A copy of the GNU General Public License can be found in the COPYRIGHT.txt
along with this program, also can be found at <http://www.gnu.org/licenses/>.
********************************************************************************/
#include "Simulation.h"
#include "Setup.h"          //For setup object

#include "EnergyTypes.h"
#include "PSFOutput.h"
#include <iostream>
#include <iomanip>

Simulation::Simulation(char const*const configFileName, MultiSim const*const& multisim):ms(multisim)
{
  startStep = 0;
  //NOTE:
  //IMPORTANT! Keep this order...
  //as system depends on staticValues, and cpu sometimes depends on both.
  set.Init(configFileName, multisim);
  totalSteps = set.config.sys.step.total;
  staticValues = new StaticVals(set);
  system = new System(*staticValues);
  staticValues->Init(set, *system);
  system->Init(set, startStep);
  //recal Init for static value for initializing ewald since ewald is
  //initialized in system
  staticValues->InitOver(set, *system);
  cpu = new CPUSide(*system, *staticValues);
  cpu->Init(set.pdb, set.config.out, set.config.sys.step.equil,
            totalSteps, startStep);

  //Dump combined PSF
  PSFOutput psfOut(staticValues->mol, *system, set.mol.kindMap,
                   set.pdb.atoms.resKindNames);
  psfOut.PrintPSF(set.config.out.state.files.psf.name);
  std::cout << "Printed combined psf to file "
            << set.config.out.state.files.psf.name << '\n';

  if(totalSteps == 0) {
    frameSteps = set.pdb.GetFrameSteps(set.config.in.files.pdb.name);
  }
#if GOMC_LIB_MPI
  PTUtils = set.config.sys.step.parallelTemp ? new ParallelTemperingUtilities(ms, *system, *staticValues, set.config.sys.step.parallelTempFreq): NULL;
  exchangeResults.resize(ms->worldSize, false);
#endif
}

Simulation::~Simulation()
{
  delete cpu;
  delete system;
  delete staticValues;
}

void Simulation::RunSimulation(void)
{
  double startEnergy = system->potential.totalEnergy.total;
  if(totalSteps == 0) {
    for(int i = 0; i < frameSteps.size(); i++) {
      if(i == 0) {
        cpu->Output(frameSteps[0] - 1);
        continue;
      }
      system->RecalculateTrajectory(set, i + 1);
      cpu->Output(frameSteps[i] - 1);
    }
  }
  for (ulong step = startStep; step < totalSteps; step++) {
    system->moveSettings.AdjustMoves(step);
    system->ChooseAndRunMove(step);
    cpu->Output(step);

    if((step + 1) == cpu->equilSteps) {
      double currEnergy = system->potential.totalEnergy.total;
      if(abs(currEnergy - startEnergy) > 1.0e+10) {
        printf("Info: Recalculating the total energies to insure the accuracy"
               " of the computed \n"
               "      running energies.\n\n");
        system->calcEwald->Init();
        system->potential = system->calcEnergy.SystemTotal();
      }
    }
  #if GOMC_LIB_MPI

    if( staticValues->simEventFreq.parallelTemp && step % staticValues->simEventFreq.parallelTempFreq == 0){

      exchangeResults = PTUtils->evaluateExchangeCriteria(step);

      if (exchangeResults[ms->worldRank] == true){
        PTUtils->exchangePositions(system->coordinates, ms, ms->worldRank-1, true);
        PTUtils->exchangeCOMs(system->com, ms, ms->worldRank-1, true);

        system->cellList.GridAll(system->boxDimRef, system->coordinates, system->molLookup);
        for (uint bPick = 0; bPick < BOX_TOTAL; bPick++){
          system->calcEwald->BoxReciprocalSetup(bPick, system->coordinates);
          system->calcEwald->UpdateRecip(bPick);
        }
        system->potential = system->calcEnergy.SystemTotal();

      } else if(ms->worldRank+1 != ms->worldSize && exchangeResults[ms->worldRank+1] == true) {
        PTUtils->exchangePositions(system->coordinates, ms, ms->worldRank+1, false);
        PTUtils->exchangeCOMs(system->com, ms, ms->worldRank+1, false);

        system->cellList.GridAll(system->boxDimRef, system->coordinates, system->molLookup);

        for (uint bPick = 0; bPick < BOX_TOTAL; bPick++){
          system->calcEwald->BoxReciprocalSetup(bPick, system->coordinates);
          system->calcEwald->UpdateRecip(bPick);
        }
        system->potential = system->calcEnergy.SystemTotal();

      }

    }
  #endif

#ifndef NDEBUG
    if((step + 1) % 1000 == 0)
      RunningCheck(step);
#endif
  }
  system->PrintAcceptance();
  system->PrintTime();
}

#ifndef NDEBUG
void Simulation::RunningCheck(const uint step)
{
  system->calcEwald->UpdateVectorsAndRecipTerms();
  SystemPotential pot = system->calcEnergy.SystemTotal();

  std::cout
      << "================================================================="
      << std::endl << "-------------------------" << std::endl
      << " STEP: " << step + 1
      << std::endl << "-------------------------" << std::endl
      << "Energy       INTRA B |     INTRA NB |        INTER |           TC |         REAL |         SELF |   CORRECTION |        RECIP"
      << std::endl
      << "System: "
      << std::setw(12) << system->potential.totalEnergy.intraBond << " | "
      << std::setw(12) << system->potential.totalEnergy.intraNonbond << " | "
      << std::setw(12) << system->potential.totalEnergy.inter << " | "
      << std::setw(12) << system->potential.totalEnergy.tc << " | "
      << std::setw(12) << system->potential.totalEnergy.real << " | "
      << std::setw(12) << system->potential.totalEnergy.self << " | "
      << std::setw(12) << system->potential.totalEnergy.correction << " | "
      << std::setw(12) << system->potential.totalEnergy.recip << std::endl
      << "Recalc: "
      << std::setw(12) << pot.totalEnergy.intraBond << " | "
      << std::setw(12) << pot.totalEnergy.intraNonbond << " | "
      << std::setw(12) << pot.totalEnergy.inter << " | "
      << std::setw(12) << pot.totalEnergy.tc << " | "
      << std::setw(12) << pot.totalEnergy.real << " | "
      << std::setw(12) << pot.totalEnergy.self << " | "
      << std::setw(12) << pot.totalEnergy.correction << " | "
      << std::setw(12) << pot.totalEnergy.recip << std::endl
      << "================================================================"
      << std::endl << std::endl;

}

#endif
<commit_msg>scorched earth ewald<commit_after>/*******************************************************************************
GPU OPTIMIZED MONTE CARLO (GOMC) 2.51
Copyright (C) 2018  GOMC Group
A copy of the GNU General Public License can be found in the COPYRIGHT.txt
along with this program, also can be found at <http://www.gnu.org/licenses/>.
********************************************************************************/
#include "Simulation.h"
#include "Setup.h"          //For setup object

#include "EnergyTypes.h"
#include "PSFOutput.h"
#include <iostream>
#include <iomanip>

Simulation::Simulation(char const*const configFileName, MultiSim const*const& multisim):ms(multisim)
{
  startStep = 0;
  //NOTE:
  //IMPORTANT! Keep this order...
  //as system depends on staticValues, and cpu sometimes depends on both.
  set.Init(configFileName, multisim);
  totalSteps = set.config.sys.step.total;
  staticValues = new StaticVals(set);
  system = new System(*staticValues);
  staticValues->Init(set, *system);
  system->Init(set, startStep);
  //recal Init for static value for initializing ewald since ewald is
  //initialized in system
  staticValues->InitOver(set, *system);
  cpu = new CPUSide(*system, *staticValues);
  cpu->Init(set.pdb, set.config.out, set.config.sys.step.equil,
            totalSteps, startStep);

  //Dump combined PSF
  PSFOutput psfOut(staticValues->mol, *system, set.mol.kindMap,
                   set.pdb.atoms.resKindNames);
  psfOut.PrintPSF(set.config.out.state.files.psf.name);
  std::cout << "Printed combined psf to file "
            << set.config.out.state.files.psf.name << '\n';

  if(totalSteps == 0) {
    frameSteps = set.pdb.GetFrameSteps(set.config.in.files.pdb.name);
  }
#if GOMC_LIB_MPI
  PTUtils = set.config.sys.step.parallelTemp ? new ParallelTemperingUtilities(ms, *system, *staticValues, set.config.sys.step.parallelTempFreq): NULL;
  exchangeResults.resize(ms->worldSize, false);
#endif
}

Simulation::~Simulation()
{
  delete cpu;
  delete system;
  delete staticValues;
}

void Simulation::RunSimulation(void)
{
  double startEnergy = system->potential.totalEnergy.total;
  if(totalSteps == 0) {
    for(int i = 0; i < frameSteps.size(); i++) {
      if(i == 0) {
        cpu->Output(frameSteps[0] - 1);
        continue;
      }
      system->RecalculateTrajectory(set, i + 1);
      cpu->Output(frameSteps[i] - 1);
    }
  }
  for (ulong step = startStep; step < totalSteps; step++) {
    system->moveSettings.AdjustMoves(step);
    system->ChooseAndRunMove(step);
    cpu->Output(step);

    if((step + 1) == cpu->equilSteps) {
      double currEnergy = system->potential.totalEnergy.total;
      if(abs(currEnergy - startEnergy) > 1.0e+10) {
        printf("Info: Recalculating the total energies to insure the accuracy"
               " of the computed \n"
               "      running energies.\n\n");
        system->calcEwald->Init();
        system->potential = system->calcEnergy.SystemTotal();
      }
    }
  #if GOMC_LIB_MPI

    if( staticValues->simEventFreq.parallelTemp && step % staticValues->simEventFreq.parallelTempFreq == 0){

      exchangeResults = PTUtils->evaluateExchangeCriteria(step);

      if (exchangeResults[ms->worldRank] == true){
        PTUtils->exchangePositions(system->coordinates, ms, ms->worldRank-1, true);
        PTUtils->exchangeCOMs(system->com, ms, ms->worldRank-1, true);

        system->cellList.GridAll(system->boxDimRef, system->coordinates, system->molLookup);

        system->calcEwald->UpdateVectorsAndRecipTerms();

        system->potential = system->calcEnergy.SystemTotal();

      } else if(ms->worldRank+1 != ms->worldSize && exchangeResults[ms->worldRank+1] == true) {
        PTUtils->exchangePositions(system->coordinates, ms, ms->worldRank+1, false);
        PTUtils->exchangeCOMs(system->com, ms, ms->worldRank+1, false);

        system->cellList.GridAll(system->boxDimRef, system->coordinates, system->molLookup);

        system->calcEwald->UpdateVectorsAndRecipTerms();

        system->potential = system->calcEnergy.SystemTotal();

      }

    }
  #endif

#ifndef NDEBUG
    if((step + 1) % 1000 == 0)
      RunningCheck(step);
#endif
  }
  system->PrintAcceptance();
  system->PrintTime();
}

#ifndef NDEBUG
void Simulation::RunningCheck(const uint step)
{
  system->calcEwald->UpdateVectorsAndRecipTerms();
  SystemPotential pot = system->calcEnergy.SystemTotal();

  std::cout
      << "================================================================="
      << std::endl << "-------------------------" << std::endl
      << " STEP: " << step + 1
      << std::endl << "-------------------------" << std::endl
      << "Energy       INTRA B |     INTRA NB |        INTER |           TC |         REAL |         SELF |   CORRECTION |        RECIP"
      << std::endl
      << "System: "
      << std::setw(12) << system->potential.totalEnergy.intraBond << " | "
      << std::setw(12) << system->potential.totalEnergy.intraNonbond << " | "
      << std::setw(12) << system->potential.totalEnergy.inter << " | "
      << std::setw(12) << system->potential.totalEnergy.tc << " | "
      << std::setw(12) << system->potential.totalEnergy.real << " | "
      << std::setw(12) << system->potential.totalEnergy.self << " | "
      << std::setw(12) << system->potential.totalEnergy.correction << " | "
      << std::setw(12) << system->potential.totalEnergy.recip << std::endl
      << "Recalc: "
      << std::setw(12) << pot.totalEnergy.intraBond << " | "
      << std::setw(12) << pot.totalEnergy.intraNonbond << " | "
      << std::setw(12) << pot.totalEnergy.inter << " | "
      << std::setw(12) << pot.totalEnergy.tc << " | "
      << std::setw(12) << pot.totalEnergy.real << " | "
      << std::setw(12) << pot.totalEnergy.self << " | "
      << std::setw(12) << pot.totalEnergy.correction << " | "
      << std::setw(12) << pot.totalEnergy.recip << std::endl
      << "================================================================"
      << std::endl << std::endl;

}

#endif
<|endoftext|>