<commit_before>//============================================================================
//==== Titre: Standard_ErrorHandler.cxx
//==== Role : class "Standard_ErrorHandler" implementation.
//============================================================================
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <Standard_ErrorHandlerCallback.hxx>
#include <Standard_Mutex.hxx>
#include <Standard.hxx>

#ifndef WNT
#include <pthread.h>
#else
#include <windows.h>
#endif

// ===========================================================================
// The class "Standard_ErrorHandler" variables
// ===========================================================================

// During [sig]setjmp()/[sig]longjmp() K_SETJMP is non zero (try)
// So if there is an abort request and if K_SETJMP is non zero, the abort
// request will be ignored. If the abort request do a raise during a setjmp
// or a longjmp, there will be a "terminating SEGV" impossible to handle.

//==== The top of the Errors Stack ===========================================
static Standard_ErrorHandler* Top = 0;

// A mutex to protect from concurrent access to Top
// Note that we should NOT use Sentry while in this class, as Sentry
// would register mutex as callback in the current exception handler
static Standard_Mutex theMutex;

static inline Standard_ThreadId GetThreadID()
{
#ifndef WNT
  return pthread_self();
#else
  return GetCurrentThreadId();
#endif
}

//============================================================================
//====  Constructor : Create a ErrorHandler structure. And add it at the
//====                'Top' of "ErrorHandler's stack".
//============================================================================

Standard_ErrorHandler::Standard_ErrorHandler () :
       myStatus(Standard_HandlerVoid), myCallbackPtr(0)
{
  myThread   = GetThreadID();

  if (Standard::IsReentrant())
    theMutex.Lock();
  myPrevious = Top;
  Top        = this;
  if (Standard::IsReentrant())
    theMutex.Unlock();
}

//============================================================================
//==== Destructor : Delete the ErrorHandler and Abort if there is a 'Error'.
//============================================================================

void Standard_ErrorHandler::Destroy()
{
  Unlink();
  if(myStatus==Standard_HandlerJumped) {
    //jumped, but not caut
    Abort();
  }
}

//=======================================================================
//function : Unlink
//purpose  :
//=======================================================================

void Standard_ErrorHandler::Unlink()
{
  // put a lock on the stack
  if (Standard::IsReentrant())
    theMutex.Lock();

  Standard_ErrorHandler* aPrevious = 0;
  Standard_ErrorHandler* aCurrent = Top;

  // locate this handler in the stack
  while(aCurrent!=0 && this!=aCurrent) {
    aPrevious = aCurrent;
    aCurrent = aCurrent->myPrevious;
  }

  if(aCurrent==0) {
    if (Standard::IsReentrant())
      theMutex.Unlock();
    return;
  }

  if(aPrevious==0) {
    // a top exception taken
    Top = aCurrent->myPrevious;
  }
  else {
    aPrevious->myPrevious=aCurrent->myPrevious;
  }
  myPrevious = 0;
  if (Standard::IsReentrant())
    theMutex.Unlock();

  // unlink and destroy all registered callbacks
  Standard_Address aPtr = aCurrent->myCallbackPtr;
  myCallbackPtr = 0;
  while ( aPtr ) {
    Standard_ErrorHandlerCallback* aCallback = (Standard_ErrorHandlerCallback*)aPtr;
    aPtr = aCallback->myNext;
    // Call destructor explicitly, as we know that it will not be called automatically
    aCallback->DestroyCallback();
  }
}

//=======================================================================
//function : IsInTryBlock
//purpose  :  test if the code is currently running in
//=======================================================================

Standard_Boolean Standard_ErrorHandler::IsInTryBlock()
{
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
  return anActive != NULL && anActive->myLabel != NULL;
}

//============================================================================
//==== Abort: make a longjmp to the saved Context.
//====    Abort if there is a non null 'Error'
//============================================================================

void Standard_ErrorHandler::Abort ()
{
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_True);

  //==== Check if can do the "longjmp" =======================================
  if(anActive == NULL || anActive->myLabel == NULL) {
    cerr << "*** Abort *** an exception was raised, but no catch was found." << endl;
    Handle(Standard_Failure) anErr =
      ( anActive != NULL && ! anActive->myCaughtError.IsNull() ?
        anActive->myCaughtError : Standard_Failure::Caught() );
    if ( ! anErr.IsNull() )
      cerr << "\t... The exception is:" << anErr->GetMessageString() << endl;
    exit(1);
  }

  anActive->myStatus = Standard_HandlerJumped;
  longjmp(anActive->myLabel, Standard_True);
}

//============================================================================
//==== Catches: If there is a 'Error', and it is in good type
//====          returns True and clean 'Error', else returns False.
//============================================================================

Standard_Boolean Standard_ErrorHandler::Catches (const Handle(Standard_Type)& AType)
{
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerJumped, Standard_False);
  if(anActive==0)
    return Standard_False;

  if(anActive->myCaughtError.IsNull())
    return Standard_False;

  if(anActive->myCaughtError->IsKind(AType)){
    myStatus=Standard_HandlerProcessed;
    return Standard_True;
  } else {
    return Standard_False;
  }
}

Handle(Standard_Failure) Standard_ErrorHandler::LastCaughtError()
{
  Handle(Standard_Failure) aHandle;
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerProcessed, Standard_False);
  if(anActive!=0)
    aHandle = anActive->myCaughtError;

  return aHandle;
}

Handle(Standard_Failure) Standard_ErrorHandler::Error() const
{
  return myCaughtError;
}

void Standard_ErrorHandler::Error(const Handle(Standard_Failure)& aError)
{
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
  if(anActive==0)
    Abort();

  anActive->myCaughtError = aError;
}

Standard_ErrorHandler* Standard_ErrorHandler::FindHandler(const Standard_HandlerStatus theStatus,
                                                          const Standard_Boolean theUnlink)
{
  // lock the stack
  if (Standard::IsReentrant())
    theMutex.Lock();

  // Find the current ErrorHandler Accordin tread
  Standard_ErrorHandler* aPrevious = 0;
  Standard_ErrorHandler* aCurrent = Top;
  Standard_ErrorHandler* anActive = 0;
  Standard_Boolean aStop = Standard_False;
  Standard_ThreadId aTreadId = GetThreadID();

  // searching an exception with correct ID number
  // which is not processed for the moment
  while(!aStop) {
    while(aCurrent!=NULL && aTreadId!=aCurrent->myThread) {
      aPrevious = aCurrent;
      aCurrent = aCurrent->myPrevious;
    }

    if(aCurrent!=NULL) {
      if(theStatus!=aCurrent->myStatus) {

        if(theUnlink) {
          //unlink current
          if(aPrevious==0) {
            // a top exception taken
            Top = aCurrent->myPrevious;
          }
          else {
            aPrevious->myPrevious=aCurrent->myPrevious;
          }
        }

        //shift
        aCurrent = aCurrent->myPrevious;
      }
      else {
	//found one
        anActive = aCurrent;
	aStop = Standard_True;
      }
    }
    else {
      //Current is NULL, means that no handlesr
      aStop = Standard_True;
    }
  }
  if (Standard::IsReentrant())
    theMutex.Unlock();

  return anActive;
}
<commit_msg>Move code to work around a BCC bug<commit_after>//============================================================================
//==== Titre: Standard_ErrorHandler.cxx
//==== Role : class "Standard_ErrorHandler" implementation.
//============================================================================
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <Standard_ErrorHandlerCallback.hxx>
#include <Standard_Mutex.hxx>
#include <Standard.hxx>

#ifndef WNT
#include <pthread.h>
#else
#include <windows.h>
#endif

// ===========================================================================
// The class "Standard_ErrorHandler" variables
// ===========================================================================

// During [sig]setjmp()/[sig]longjmp() K_SETJMP is non zero (try)
// So if there is an abort request and if K_SETJMP is non zero, the abort
// request will be ignored. If the abort request do a raise during a setjmp
// or a longjmp, there will be a "terminating SEGV" impossible to handle.

//Somehow borland needs this inline global function to be declared first ... ??
static inline Standard_ThreadId GetThreadID()
{
#ifndef WNT
  return pthread_self();
#else
  return GetCurrentThreadId();
#endif
}

//==== The top of the Errors Stack ===========================================
static Standard_ErrorHandler* Top = 0;

// A mutex to protect from concurrent access to Top
// Note that we should NOT use Sentry while in this class, as Sentry
// would register mutex as callback in the current exception handler
static Standard_Mutex theMutex;

//============================================================================
//====  Constructor : Create a ErrorHandler structure. And add it at the
//====                'Top' of "ErrorHandler's stack".
//============================================================================

Standard_ErrorHandler::Standard_ErrorHandler () :
       myStatus(Standard_HandlerVoid), myCallbackPtr(0)
{
  myThread   = GetThreadID();

  if (Standard::IsReentrant())
    theMutex.Lock();
  myPrevious = Top;
  Top        = this;
  if (Standard::IsReentrant())
    theMutex.Unlock();
}

//============================================================================
//==== Destructor : Delete the ErrorHandler and Abort if there is a 'Error'.
//============================================================================

void Standard_ErrorHandler::Destroy()
{
  Unlink();
  if(myStatus==Standard_HandlerJumped) {
    //jumped, but not caut
    Abort();
  }
}

//=======================================================================
//function : Unlink
//purpose  :
//=======================================================================

void Standard_ErrorHandler::Unlink()
{
  // put a lock on the stack
  if (Standard::IsReentrant())
    theMutex.Lock();

  Standard_ErrorHandler* aPrevious = 0;
  Standard_ErrorHandler* aCurrent = Top;

  // locate this handler in the stack
  while(aCurrent!=0 && this!=aCurrent) {
    aPrevious = aCurrent;
    aCurrent = aCurrent->myPrevious;
  }

  if(aCurrent==0) {
    if (Standard::IsReentrant())
      theMutex.Unlock();
    return;
  }

  if(aPrevious==0) {
    // a top exception taken
    Top = aCurrent->myPrevious;
  }
  else {
    aPrevious->myPrevious=aCurrent->myPrevious;
  }
  myPrevious = 0;
  if (Standard::IsReentrant())
    theMutex.Unlock();

  // unlink and destroy all registered callbacks
  Standard_Address aPtr = aCurrent->myCallbackPtr;
  myCallbackPtr = 0;
  while ( aPtr ) {
    Standard_ErrorHandlerCallback* aCallback = (Standard_ErrorHandlerCallback*)aPtr;
    aPtr = aCallback->myNext;
    // Call destructor explicitly, as we know that it will not be called automatically
    aCallback->DestroyCallback();
  }
}

//=======================================================================
//function : IsInTryBlock
//purpose  :  test if the code is currently running in
//=======================================================================

Standard_Boolean Standard_ErrorHandler::IsInTryBlock()
{
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
  return anActive != NULL && anActive->myLabel != NULL;
}

//============================================================================
//==== Abort: make a longjmp to the saved Context.
//====    Abort if there is a non null 'Error'
//============================================================================

void Standard_ErrorHandler::Abort ()
{
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_True);

  //==== Check if can do the "longjmp" =======================================
  if(anActive == NULL || anActive->myLabel == NULL) {
    cerr << "*** Abort *** an exception was raised, but no catch was found." << endl;
    Handle(Standard_Failure) anErr =
      ( anActive != NULL && ! anActive->myCaughtError.IsNull() ?
        anActive->myCaughtError : Standard_Failure::Caught() );
    if ( ! anErr.IsNull() )
      cerr << "\t... The exception is:" << anErr->GetMessageString() << endl;
    exit(1);
  }

  anActive->myStatus = Standard_HandlerJumped;
  longjmp(anActive->myLabel, Standard_True);
}

//============================================================================
//==== Catches: If there is a 'Error', and it is in good type
//====          returns True and clean 'Error', else returns False.
//============================================================================

Standard_Boolean Standard_ErrorHandler::Catches (const Handle(Standard_Type)& AType)
{
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerJumped, Standard_False);
  if(anActive==0)
    return Standard_False;

  if(anActive->myCaughtError.IsNull())
    return Standard_False;

  if(anActive->myCaughtError->IsKind(AType)){
    myStatus=Standard_HandlerProcessed;
    return Standard_True;
  } else {
    return Standard_False;
  }
}

Handle(Standard_Failure) Standard_ErrorHandler::LastCaughtError()
{
  Handle(Standard_Failure) aHandle;
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerProcessed, Standard_False);
  if(anActive!=0)
    aHandle = anActive->myCaughtError;

  return aHandle;
}

Handle(Standard_Failure) Standard_ErrorHandler::Error() const
{
  return myCaughtError;
}

void Standard_ErrorHandler::Error(const Handle(Standard_Failure)& aError)
{
  Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
  if(anActive==0)
    Abort();

  anActive->myCaughtError = aError;
}

Standard_ErrorHandler* Standard_ErrorHandler::FindHandler(const Standard_HandlerStatus theStatus,
                                                          const Standard_Boolean theUnlink)
{
  // lock the stack
  if (Standard::IsReentrant())
    theMutex.Lock();

  // Find the current ErrorHandler Accordin tread
  Standard_ErrorHandler* aPrevious = 0;
  Standard_ErrorHandler* aCurrent = Top;
  Standard_ErrorHandler* anActive = 0;
  Standard_Boolean aStop = Standard_False;
  Standard_ThreadId aTreadId = GetThreadID();

  // searching an exception with correct ID number
  // which is not processed for the moment
  while(!aStop) {
    while(aCurrent!=NULL && aTreadId!=aCurrent->myThread) {
      aPrevious = aCurrent;
      aCurrent = aCurrent->myPrevious;
    }

    if(aCurrent!=NULL) {
      if(theStatus!=aCurrent->myStatus) {

        if(theUnlink) {
          //unlink current
          if(aPrevious==0) {
            // a top exception taken
            Top = aCurrent->myPrevious;
          }
          else {
            aPrevious->myPrevious=aCurrent->myPrevious;
          }
        }

        //shift
        aCurrent = aCurrent->myPrevious;
      }
      else {
	//found one
        anActive = aCurrent;
	aStop = Standard_True;
      }
    }
    else {
      //Current is NULL, means that no handlesr
      aStop = Standard_True;
    }
  }
  if (Standard::IsReentrant())
    theMutex.Unlock();

  return anActive;
}
<|endoftext|>


<commit_before>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache license,    |
 | that is bundled with this package in the file LICENSE, and is        |
 | available through the world-wide-web at the following url:           |
 | http://www.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | license@swoole.com so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
 +----------------------------------------------------------------------+
 */

#include "swoole_api.h"
#include "async.h"

#include <thread>
#include <atomic>
#include <unordered_map>
#include <condition_variable>
#include <mutex>
#include <queue>

using namespace std;

typedef swAio_event async_event;

swAsyncIO SwooleAIO;

static void swAio_free(void *private_data);

int swAio_callback(swReactor *reactor, swEvent *_event)
{
    int i;
    async_event *events[SW_AIO_EVENT_NUM];
    ssize_t n = read(_event->fd, events, sizeof(async_event*) * SW_AIO_EVENT_NUM);
    if (n < 0)
    {
        swSysWarn("read() failed");
        return SW_ERR;
    }
    for (i = 0; i < n / (int) sizeof(async_event*); i++)
    {
        if (!events[i]->canceled)
        {
            events[i]->callback(events[i]);
        }
        SwooleAIO.task_num--;
        delete events[i];
    }
    return SW_OK;
}

struct thread_context
{
    thread *_thread;
    atomic<bool> *_exit_flag;
    thread_context(thread *_thread, atomic<bool> *_exit_flag) : _thread(_thread), _exit_flag(_exit_flag) { }
};

class async_event_queue
{
public:
    inline bool push(async_event *event)
    {
        unique_lock<mutex> lock(_mutex);
        _queue.push(event);
        return true;
    }
    inline async_event* pop()
    {
        unique_lock<mutex> lock(_mutex);
        if (_queue.empty())
        {
            return nullptr;
        }
        async_event* retval = _queue.front();
        _queue.pop();
        return retval;
    }
    inline bool empty()
    {
        unique_lock<mutex> lock(_mutex);
        return _queue.empty();
    }
    inline size_t count()
    {
        return _queue.size();
    }
private:
    queue<async_event*> _queue;
    mutex _mutex;
};

class async_thread_pool
{
public:
    async_thread_pool(size_t _min_threads, size_t _max_threads)
    {
        n_waiting = 0;
        running = false;
        min_threads = _min_threads;
        max_threads = _max_threads;
        current_task_id = 0;
        current_pid = getpid();

        if (swPipeBase_create(&_aio_pipe, 0) < 0)
        {
            swoole_throw_error(SW_ERROR_SYSTEM_CALL_FAIL);
        }
        _pipe_read = _aio_pipe.getFd(&_aio_pipe, 0);
        _pipe_write = _aio_pipe.getFd(&_aio_pipe, 1);
        swoole_event_add(_pipe_read, SW_EVENT_READ, SW_FD_AIO);
    }

    ~async_thread_pool()
    {
        shutdown();
        if (SwooleTG.reactor)
        {
            swoole_event_del(_pipe_read);
        }
        _aio_pipe.close(&_aio_pipe);
    }

    void schedule()
    {
        //++
        if (n_waiting == 0 && threads.size() < max_threads)
        {
            create_thread();
        }
        //--
        else if (n_waiting > min_threads)
        {
            thread_context *tc = &threads.front();
            *tc->_exit_flag = false;
            tc->_thread->detach();
            delete tc->_thread;
            threads.pop();
        }
    }

    bool start()
    {
        running = true;
        for (size_t i = 0; i < min_threads; i++)
        {
            create_thread();
        }
        return true;
    }

    bool shutdown()
    {
        if (!running)
        {
            return false;
        }
        running = false;

        _mutex.lock();
        _cv.notify_all();
        _mutex.unlock();

        while (!threads.empty())
        {
            thread_context *tc = &threads.front();
            if (tc->_thread->joinable())
            {
                tc->_thread->join();
            }
            threads.pop();
        }

        return true;
    }

    async_event* dispatch(const async_event *request)
    {
        auto _event_copy = new async_event(*request);
        schedule();
        _event_copy->task_id = current_task_id++;
        _queue.push(_event_copy);
        _cv.notify_one();
        return _event_copy;
    }

    inline size_t thread_count()
    {
        return threads.size();
    }

    inline size_t queue_count()
    {
        return _queue.count();
    }

    pid_t current_pid;

private:
    void create_thread()
    {
        atomic<bool> *exit_flag = new atomic<bool>(false);
        try
        {
            thread *_thread = new thread([this, &exit_flag]()
            {
                SwooleTG.buffer_stack = swString_new(SW_STACK_BUFFER_SIZE);
                if (SwooleTG.buffer_stack == nullptr)
                {
                    return;
                }

                swSignal_none();

                while (running)
                {
                    async_event *event;
                    event = _queue.pop();
                    if (event)
                    {
                        if (sw_unlikely(event->handler == nullptr))
                        {
                            event->error = SW_ERROR_AIO_BAD_REQUEST;
                            event->ret = -1;
                            goto _error;
                        }
                        else if (sw_unlikely(event->canceled))
                        {
                            event->error = SW_ERROR_AIO_BAD_REQUEST;
                            event->ret = -1;
                            goto _error;
                        }
                        else
                        {
                            event->handler(event);
                        }

                        swTrace("aio_thread ok. ret=%d, error=%d", event->ret, event->error);

                        _error:
                        while (true)
                        {
                            SwooleAIO.lock.lock(&SwooleAIO.lock);
                            int ret = write(_pipe_write, &event, sizeof(event));
                            SwooleAIO.lock.unlock(&SwooleAIO.lock);
                            if (ret < 0)
                            {
                                if (errno == EAGAIN)
                                {
                                    swSocket_wait(_pipe_write, 1000, SW_EVENT_WRITE);
                                    continue;
                                }
                                else if (errno == EINTR)
                                {
                                    continue;
                                }
                                else
                                {
                                    swSysWarn("sendto swoole_aio_pipe_write failed");
                                }
                            }
                            break;
                        }

                        // exit
                        if (*exit_flag)
                        {
                            break;
                        }
                    }
                    else
                    {
                        unique_lock<mutex> lock(_mutex);
                        if (running)
                        {
                            ++n_waiting;
                            _cv.wait(lock);
                            --n_waiting;
                        }
                    }
                }

                delete exit_flag;
            });
            threads.push(thread_context(_thread, exit_flag));
        }
        catch (const std::system_error& e)
        {
            swSysNotice("create aio thread failed, please check your system configuration or adjust max_thread_count");
            delete exit_flag;
            return;
        }
    }

    size_t min_threads;
    size_t max_threads;

    swPipe _aio_pipe;
    int _pipe_read;
    int _pipe_write;
    int current_task_id;

    queue<thread_context> threads;
    async_event_queue _queue;
    bool running;
    atomic<int> n_waiting;
    mutex _mutex;
    condition_variable _cv;
};

static async_thread_pool *pool = nullptr;

static int swAio_init()
{
    if (SwooleAIO.init)
    {
        swWarn("AIO has already been initialized");
        return SW_ERR;
    }
    if (!SwooleTG.reactor)
    {
        swWarn("no event loop, cannot initialized");
        return SW_ERR;
    }

    if (swMutex_create(&SwooleAIO.lock, 0) < 0)
    {
        swWarn("create mutex lock error");
        return SW_ERR;
    }

    if (SwooleAIO.min_thread_num == 0)
    {
        SwooleAIO.min_thread_num = SW_AIO_THREAD_DEFAULT_NUM;
    }
    if (SwooleAIO.max_thread_num == 0)
    {
        SwooleAIO.max_thread_num = (SW_CPU_NUM * 2) * SW_AIO_THREAD_NUM_MULTIPLE;
    }
    if (SwooleAIO.min_thread_num > SwooleAIO.max_thread_num)
    {
        SwooleAIO.max_thread_num = SwooleAIO.min_thread_num;
    }

    swReactor_add_destroy_callback(SwooleTG.reactor, swAio_free, nullptr);

    pool = new async_thread_pool(SwooleAIO.min_thread_num, SwooleAIO.max_thread_num);
    pool->start();
    SwooleAIO.init = 1;

    return SW_OK;
}

size_t swAio_thread_count()
{
    return pool ? pool->thread_count() : 0;
}

int swAio_dispatch(const swAio_event *request)
{
    if (sw_unlikely(!SwooleAIO.init))
    {
        swAio_init();
    }
    SwooleAIO.task_num++;
    async_event *event = pool->dispatch(request);
    return event->task_id;
}

swAio_event* swAio_dispatch2(const swAio_event *request)
{
    if (sw_unlikely(!SwooleAIO.init))
    {
        swAio_init();
    }
    SwooleAIO.task_num++;
    return pool->dispatch(request);
}

static void swAio_free(void *private_data)
{
    if (!SwooleAIO.init)
    {
        return;
    }
    if (pool->current_pid == getpid())
    {
        delete pool;
    }
    pool = nullptr;
    SwooleAIO.init = 0;
}
<commit_msg>Fix warning<commit_after>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache license,    |
 | that is bundled with this package in the file LICENSE, and is        |
 | available through the world-wide-web at the following url:           |
 | http://www.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | license@swoole.com so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
 +----------------------------------------------------------------------+
 */

#include "swoole_api.h"
#include "async.h"

#include <thread>
#include <atomic>
#include <unordered_map>
#include <condition_variable>
#include <mutex>
#include <queue>

using namespace std;

typedef swAio_event async_event;

swAsyncIO SwooleAIO;

static void swAio_free(void *private_data);

int swAio_callback(swReactor *reactor, swEvent *_event)
{
    async_event *events[SW_AIO_EVENT_NUM];
    ssize_t n = read(_event->fd, events, sizeof(async_event*) * SW_AIO_EVENT_NUM);
    if (n < 0)
    {
        swSysWarn("read() failed");
        return SW_ERR;
    }
    for (size_t i = 0; i < n / sizeof(async_event *); i++)
    {
        if (!events[i]->canceled)
        {
            events[i]->callback(events[i]);
        }
        SwooleAIO.task_num--;
        delete events[i];
    }
    return SW_OK;
}

struct thread_context
{
    thread *_thread;
    atomic<bool> *_exit_flag;
    thread_context(thread *_thread, atomic<bool> *_exit_flag) : _thread(_thread), _exit_flag(_exit_flag) { }
};

class async_event_queue
{
public:
    inline bool push(async_event *event)
    {
        unique_lock<mutex> lock(_mutex);
        _queue.push(event);
        return true;
    }
    inline async_event* pop()
    {
        unique_lock<mutex> lock(_mutex);
        if (_queue.empty())
        {
            return nullptr;
        }
        async_event* retval = _queue.front();
        _queue.pop();
        return retval;
    }
    inline bool empty()
    {
        unique_lock<mutex> lock(_mutex);
        return _queue.empty();
    }
    inline size_t count()
    {
        return _queue.size();
    }
private:
    queue<async_event*> _queue;
    mutex _mutex;
};

class async_thread_pool
{
public:
    async_thread_pool(size_t _min_threads, size_t _max_threads)
    {
        n_waiting = 0;
        running = false;
        min_threads = _min_threads;
        max_threads = _max_threads;
        current_task_id = 0;
        current_pid = getpid();

        if (swPipeBase_create(&_aio_pipe, 0) < 0)
        {
            swoole_throw_error(SW_ERROR_SYSTEM_CALL_FAIL);
        }
        _pipe_read = _aio_pipe.getFd(&_aio_pipe, 0);
        _pipe_write = _aio_pipe.getFd(&_aio_pipe, 1);
        swoole_event_add(_pipe_read, SW_EVENT_READ, SW_FD_AIO);
    }

    ~async_thread_pool()
    {
        shutdown();
        if (SwooleTG.reactor)
        {
            swoole_event_del(_pipe_read);
        }
        _aio_pipe.close(&_aio_pipe);
    }

    void schedule()
    {
        //++
        if (n_waiting == 0 && threads.size() < max_threads)
        {
            create_thread();
        }
        //--
        else if (n_waiting > min_threads)
        {
            thread_context *tc = &threads.front();
            *tc->_exit_flag = false;
            tc->_thread->detach();
            delete tc->_thread;
            threads.pop();
        }
    }

    bool start()
    {
        running = true;
        for (size_t i = 0; i < min_threads; i++)
        {
            create_thread();
        }
        return true;
    }

    bool shutdown()
    {
        if (!running)
        {
            return false;
        }
        running = false;

        _mutex.lock();
        _cv.notify_all();
        _mutex.unlock();

        while (!threads.empty())
        {
            thread_context *tc = &threads.front();
            if (tc->_thread->joinable())
            {
                tc->_thread->join();
            }
            threads.pop();
        }

        return true;
    }

    async_event* dispatch(const async_event *request)
    {
        auto _event_copy = new async_event(*request);
        schedule();
        _event_copy->task_id = current_task_id++;
        _queue.push(_event_copy);
        _cv.notify_one();
        return _event_copy;
    }

    inline size_t thread_count()
    {
        return threads.size();
    }

    inline size_t queue_count()
    {
        return _queue.count();
    }

    pid_t current_pid;

private:
    void create_thread()
    {
        atomic<bool> *exit_flag = new atomic<bool>(false);
        try
        {
            thread *_thread = new thread([this, &exit_flag]()
            {
                SwooleTG.buffer_stack = swString_new(SW_STACK_BUFFER_SIZE);
                if (SwooleTG.buffer_stack == nullptr)
                {
                    return;
                }

                swSignal_none();

                while (running)
                {
                    async_event *event;
                    event = _queue.pop();
                    if (event)
                    {
                        if (sw_unlikely(event->handler == nullptr))
                        {
                            event->error = SW_ERROR_AIO_BAD_REQUEST;
                            event->ret = -1;
                            goto _error;
                        }
                        else if (sw_unlikely(event->canceled))
                        {
                            event->error = SW_ERROR_AIO_BAD_REQUEST;
                            event->ret = -1;
                            goto _error;
                        }
                        else
                        {
                            event->handler(event);
                        }

                        swTrace("aio_thread ok. ret=%d, error=%d", event->ret, event->error);

                        _error:
                        while (true)
                        {
                            SwooleAIO.lock.lock(&SwooleAIO.lock);
                            int ret = write(_pipe_write, &event, sizeof(event));
                            SwooleAIO.lock.unlock(&SwooleAIO.lock);
                            if (ret < 0)
                            {
                                if (errno == EAGAIN)
                                {
                                    swSocket_wait(_pipe_write, 1000, SW_EVENT_WRITE);
                                    continue;
                                }
                                else if (errno == EINTR)
                                {
                                    continue;
                                }
                                else
                                {
                                    swSysWarn("sendto swoole_aio_pipe_write failed");
                                }
                            }
                            break;
                        }

                        // exit
                        if (*exit_flag)
                        {
                            break;
                        }
                    }
                    else
                    {
                        unique_lock<mutex> lock(_mutex);
                        if (running)
                        {
                            ++n_waiting;
                            _cv.wait(lock);
                            --n_waiting;
                        }
                    }
                }

                delete exit_flag;
            });
            threads.push(thread_context(_thread, exit_flag));
        }
        catch (const std::system_error& e)
        {
            swSysNotice("create aio thread failed, please check your system configuration or adjust max_thread_count");
            delete exit_flag;
            return;
        }
    }

    size_t min_threads;
    size_t max_threads;

    swPipe _aio_pipe;
    int _pipe_read;
    int _pipe_write;
    int current_task_id;

    queue<thread_context> threads;
    async_event_queue _queue;
    bool running;
    atomic<size_t> n_waiting;
    mutex _mutex;
    condition_variable _cv;
};

static async_thread_pool *pool = nullptr;

static int swAio_init()
{
    if (SwooleAIO.init)
    {
        swWarn("AIO has already been initialized");
        return SW_ERR;
    }
    if (!SwooleTG.reactor)
    {
        swWarn("no event loop, cannot initialized");
        return SW_ERR;
    }

    if (swMutex_create(&SwooleAIO.lock, 0) < 0)
    {
        swWarn("create mutex lock error");
        return SW_ERR;
    }

    if (SwooleAIO.min_thread_num == 0)
    {
        SwooleAIO.min_thread_num = SW_AIO_THREAD_DEFAULT_NUM;
    }
    if (SwooleAIO.max_thread_num == 0)
    {
        SwooleAIO.max_thread_num = (SW_CPU_NUM * 2) * SW_AIO_THREAD_NUM_MULTIPLE;
    }
    if (SwooleAIO.min_thread_num > SwooleAIO.max_thread_num)
    {
        SwooleAIO.max_thread_num = SwooleAIO.min_thread_num;
    }

    swReactor_add_destroy_callback(SwooleTG.reactor, swAio_free, nullptr);

    pool = new async_thread_pool(SwooleAIO.min_thread_num, SwooleAIO.max_thread_num);
    pool->start();
    SwooleAIO.init = 1;

    return SW_OK;
}

size_t swAio_thread_count()
{
    return pool ? pool->thread_count() : 0;
}

int swAio_dispatch(const swAio_event *request)
{
    if (sw_unlikely(!SwooleAIO.init))
    {
        swAio_init();
    }
    SwooleAIO.task_num++;
    async_event *event = pool->dispatch(request);
    return event->task_id;
}

swAio_event* swAio_dispatch2(const swAio_event *request)
{
    if (sw_unlikely(!SwooleAIO.init))
    {
        swAio_init();
    }
    SwooleAIO.task_num++;
    return pool->dispatch(request);
}

static void swAio_free(void *private_data)
{
    if (!SwooleAIO.init)
    {
        return;
    }
    if (pool->current_pid == getpid())
    {
        delete pool;
    }
    pool = nullptr;
    SwooleAIO.init = 0;
}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>
    Copyright © 2015
              Jonathan Hale <squareys@googlemail.com>

    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 <memory.h>
#include <Corrade/Containers/Array.h>
#include <Magnum/Magnum.h>
#include <Magnum/Math/Vector2.h>
#include <Magnum/Math/Vector3.h>
#include <Magnum/Mesh.h>
#include <Corrade/Utility/utilities.h>
#include <Magnum/Buffer.h>
#include <Magnum/DefaultFramebuffer.h>
#include <Magnum/Renderer.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Primitives/Cube.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/Trade/MeshData3D.h>
#include <Magnum/Math/Quaternion.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/Framebuffer.h>
#include <Magnum/Renderbuffer.h>
#include <Magnum/Texture.h>
#include <Magnum/TextureFormat.h>
#include <Magnum/Context.h>

#include "Types.h"
#include "HmdCamera.h"
#include "CubeDrawable.h"

#include <Magnum/LibOvrIntegration/LibOvrIntegration.h>
#include <Magnum/LibOvrIntegration/Context.h>
#include <Magnum/LibOvrIntegration/Hmd.h>
#include <Magnum/LibOvrIntegration/HmdEnum.h>

namespace Magnum { namespace Examples {

using namespace LibOvrIntegration;

/**
 * @brief The Application class of OvrExample.
 * @author Jonathan Hale (Squareys)
 */
class OvrExample: public Platform::Application {
    public:
        explicit OvrExample(const Arguments& arguments);
        virtual ~OvrExample();

    protected:
        virtual void keyPressEvent(KeyEvent& event) override;

    private:
        void drawEvent() override;

        LibOvrIntegration::Context _ovrContext;
        std::unique_ptr<Hmd> _hmd;

        std::unique_ptr<Buffer> _indexBuffer, _vertexBuffer;
        std::unique_ptr<Mesh> _mesh;
        std::unique_ptr<Shaders::Phong> _shader;

        Scene3D _scene;
        Object3D _cameraObject;
        Object3D _eyes[2];
        SceneGraph::DrawableGroup3D _drawables;
        std::unique_ptr<HmdCamera> _cameras[2];

        std::unique_ptr<Object3D> _cubes[4];
        std::unique_ptr<CubeDrawable> _cubeDrawables[4];

        std::unique_ptr<Framebuffer> _mirrorFramebuffer;
        Texture2D* _mirrorTexture;

        LayerEyeFov* _layer;

        PerformanceHudMode _curPerfHudMode;
};

OvrExample::OvrExample(const Arguments& arguments) : Platform::Application(arguments, nullptr),
    _indexBuffer(nullptr), _vertexBuffer(nullptr), _mesh(nullptr),
    _shader(nullptr), _scene(), _cameraObject(&_scene), _curPerfHudMode(PerformanceHudMode::Off)
{

    /* connect to an Hmd, or create a debug hmd with DK2 type in case none is connected. */
    _hmd = LibOvrIntegration::Context::get().createHmd(0, HmdType::DK2);

    /* get the hmd display resolution */
    Vector2i resolution = _hmd->resolution() / 2;

    /* create a context with the hmd display resolution */
    Configuration conf;
    conf.setTitle("Magnum OculusVR Example")
        .setSize(resolution)
        .setSampleCount(16);

    if(!tryCreateContext(conf))
        createContext(conf.setSampleCount(0));

    /* the oculus sdk compositor does some "magic" to reduce latency. For
     * that to work, vsync needs to be turned off. */
    if(!setSwapInterval(0))
        Error() << "Could not turn off vsync.";

    Renderer::enable(Renderer::Feature::DepthTest);

    _hmd->setEnabledCaps(HmdCapability::LowPersistence | HmdCapability::DynamicPrediction );
    _hmd->configureTracking(HmdTrackingCapability::Orientation | HmdTrackingCapability::MagYawCorrection |
                            HmdTrackingCapability::Position, {});
    _hmd->configureRendering();

    /* setup mirroring of oculus sdk compositor results to a texture which can later be blitted
     * onto the defaultFramebuffer. */
    _mirrorTexture = &_hmd->createMirrorTexture(TextureFormat::RGBA, resolution);
    _mirrorFramebuffer.reset(new Framebuffer(Range2Di::fromSize({}, resolution)));
    _mirrorFramebuffer->attachTexture(Framebuffer::ColorAttachment(0), *_mirrorTexture, 0)
                      .mapForRead(Framebuffer::ColorAttachment(0));

    /* Setup cube mesh. */
    const Trade::MeshData3D cube = Primitives::Cube::solid();

    _vertexBuffer.reset(new Buffer());
    _vertexBuffer->setData(
                MeshTools::interleave(cube.positions(0), cube.normals(0)),
                BufferUsage::StaticDraw);

    Containers::Array<char> indexData;
    Mesh::IndexType indexType;
    UnsignedInt indexStart, indexEnd;
    std::tie(indexData, indexType, indexStart, indexEnd) =
            MeshTools::compressIndices(cube.indices());

    _indexBuffer.reset(new Buffer());
    _indexBuffer->setData(indexData, BufferUsage::StaticDraw);

    _mesh.reset(new Mesh());
    _mesh->setPrimitive(cube.primitive()).setCount(cube.indices().size()).addVertexBuffer(
                *_vertexBuffer, 0, Shaders::Phong::Position {},
                Shaders::Phong::Normal {}).setIndexBuffer(*_indexBuffer, 0, indexType,
                                                          indexStart, indexEnd);

    /* setup shader */
    _shader.reset(new Shaders::Phong());

    /* setup scene */
    _cubes[0] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[0]->rotateY(Deg(45.0f));
    _cubes[0]->translate({0.0f, 0.0f, -3.0f});
    _cubeDrawables[0] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {1.0f, 1.0f, 0.0f}, _cubes[0].get(), &_drawables));

    _cubes[1] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[1]->rotateY(Deg(45.0f));
    _cubes[1]->translate({5.0f, 0.0f, 0.0f});
    _cubeDrawables[1] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {1.0f, 0.0f, 0.0f}, _cubes[1].get(), &_drawables));

    _cubes[2] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[2]->rotateY(Deg(45.0f));
    _cubes[2]->translate({-10.0f, 0.0f, 0.0f});
    _cubeDrawables[2] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {0.0f, 0.0f, 1.0f}, _cubes[2].get(), &_drawables));

    _cubes[3] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[3]->rotateY(Deg(45.0f));
    _cubes[3]->translate({0.0f, 0.0f, 7.0f});
    _cubeDrawables[3] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {0.0f, 1.0f, 1.0f}, _cubes[3].get(), &_drawables));

    /* setup compositor layers */
    _layer = &LibOvrIntegration::Context::get().compositor().addLayerEyeFov();
    _layer->setFov(*_hmd.get());
    _layer->setHighQuality(true);

    /* setup cameras */
    _eyes[0].setParent(&_cameraObject);
    _eyes[1].setParent(&_cameraObject);

    for(int eye = 0; eye < 2; ++eye) {
        /* projection matrix is set in the camera, since it requires some hmd-specific fov etc. */
        _cameras[eye].reset(new HmdCamera(*_hmd, eye, _eyes[eye]));

        _layer->setColorTexture(eye, _cameras[eye]->textureSet());
        _layer->setViewport(eye, {{}, _cameras[eye]->viewport()});
    }

}

OvrExample::~OvrExample() {
}

void OvrExample::drawEvent() {
    /* get orientation and position of the hmd. */
    std::array<DualQuaternion, 2> poses = _hmd->pollEyePoses().eyePoses();

    /* draw the scene for both cameras */
    for(int eye = 0; eye < 2; ++eye) {
        /* set the transformation according to rift trackers */
        _eyes[eye].setTransformation(poses[eye].toMatrix());
        /* render each eye. */
        _cameras[eye]->draw(_drawables);
    }

    /* set the layers eye poses to the poses chached in the _hmd. */
    _layer->setRenderPoses(*_hmd.get());

    /* let the libOVR sdk compositor do its magic! */
    LibOvrIntegration::Context::get().compositor().submitFrame(*_hmd.get());

    /* blit mirror texture to defaultFramebuffer. */
    const Vector2i size = _mirrorTexture->imageSize(0);
    Framebuffer::blit(*_mirrorFramebuffer,
                      defaultFramebuffer,
                      {{0, size.y()}, {size.x(), 0}},
                      {{}, size},
                      FramebufferBlit::Color, FramebufferBlitFilter::Nearest);

    if(_hmd->isDebugHmd()) {
        /* provide some rotation, but only without real devices to avoid vr sickness ;) */
        _cameraObject.rotateY(Deg(0.1f));
    }

    swapBuffers();
    redraw();
}

void OvrExample::keyPressEvent(KeyEvent& event) {
    if(event.key() == KeyEvent::Key::F11) {
        /* toggle through the performance hud modes */
        switch(_curPerfHudMode) {
            case PerformanceHudMode::Off:
                _curPerfHudMode = PerformanceHudMode::LatencyTiming;
                break;
            case PerformanceHudMode::LatencyTiming:
                _curPerfHudMode = PerformanceHudMode::RenderTiming;
                break;
            case PerformanceHudMode::RenderTiming:
                _curPerfHudMode = PerformanceHudMode::Off;
                break;
        }

        /** libovr has a bug where performance hud will block the app when using a debug hmd */
        if(!_hmd->isDebugHmd()) {
            _hmd->setPerformanceHudMode(_curPerfHudMode);
        }
    }
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::OvrExample)
<commit_msg>ovr: Exit application on Esc.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>
    Copyright © 2015
              Jonathan Hale <squareys@googlemail.com>

    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 <memory.h>
#include <Corrade/Containers/Array.h>
#include <Magnum/Magnum.h>
#include <Magnum/Math/Vector2.h>
#include <Magnum/Math/Vector3.h>
#include <Magnum/Mesh.h>
#include <Corrade/Utility/utilities.h>
#include <Magnum/Buffer.h>
#include <Magnum/DefaultFramebuffer.h>
#include <Magnum/Renderer.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Primitives/Cube.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/Trade/MeshData3D.h>
#include <Magnum/Math/Quaternion.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/Framebuffer.h>
#include <Magnum/Renderbuffer.h>
#include <Magnum/Texture.h>
#include <Magnum/TextureFormat.h>
#include <Magnum/Context.h>

#include "Types.h"
#include "HmdCamera.h"
#include "CubeDrawable.h"

#include <Magnum/LibOvrIntegration/LibOvrIntegration.h>
#include <Magnum/LibOvrIntegration/Context.h>
#include <Magnum/LibOvrIntegration/Hmd.h>
#include <Magnum/LibOvrIntegration/HmdEnum.h>

namespace Magnum { namespace Examples {

using namespace LibOvrIntegration;

/**
 * @brief The Application class of OvrExample.
 * @author Jonathan Hale (Squareys)
 */
class OvrExample: public Platform::Application {
    public:
        explicit OvrExample(const Arguments& arguments);
        virtual ~OvrExample();

    protected:
        virtual void keyPressEvent(KeyEvent& event) override;

    private:
        void drawEvent() override;

        LibOvrIntegration::Context _ovrContext;
        std::unique_ptr<Hmd> _hmd;

        std::unique_ptr<Buffer> _indexBuffer, _vertexBuffer;
        std::unique_ptr<Mesh> _mesh;
        std::unique_ptr<Shaders::Phong> _shader;

        Scene3D _scene;
        Object3D _cameraObject;
        Object3D _eyes[2];
        SceneGraph::DrawableGroup3D _drawables;
        std::unique_ptr<HmdCamera> _cameras[2];

        std::unique_ptr<Object3D> _cubes[4];
        std::unique_ptr<CubeDrawable> _cubeDrawables[4];

        std::unique_ptr<Framebuffer> _mirrorFramebuffer;
        Texture2D* _mirrorTexture;

        LayerEyeFov* _layer;

        PerformanceHudMode _curPerfHudMode;
};

OvrExample::OvrExample(const Arguments& arguments) : Platform::Application(arguments, nullptr),
    _indexBuffer(nullptr), _vertexBuffer(nullptr), _mesh(nullptr),
    _shader(nullptr), _scene(), _cameraObject(&_scene), _curPerfHudMode(PerformanceHudMode::Off)
{

    /* connect to an Hmd, or create a debug hmd with DK2 type in case none is connected. */
    _hmd = LibOvrIntegration::Context::get().createHmd(0, HmdType::DK2);

    /* get the hmd display resolution */
    Vector2i resolution = _hmd->resolution() / 2;

    /* create a context with the hmd display resolution */
    Configuration conf;
    conf.setTitle("Magnum OculusVR Example")
        .setSize(resolution)
        .setSampleCount(16);

    if(!tryCreateContext(conf))
        createContext(conf.setSampleCount(0));

    /* the oculus sdk compositor does some "magic" to reduce latency. For
     * that to work, vsync needs to be turned off. */
    if(!setSwapInterval(0))
        Error() << "Could not turn off vsync.";

    Renderer::enable(Renderer::Feature::DepthTest);

    _hmd->setEnabledCaps(HmdCapability::LowPersistence | HmdCapability::DynamicPrediction );
    _hmd->configureTracking(HmdTrackingCapability::Orientation | HmdTrackingCapability::MagYawCorrection |
                            HmdTrackingCapability::Position, {});
    _hmd->configureRendering();

    /* setup mirroring of oculus sdk compositor results to a texture which can later be blitted
     * onto the defaultFramebuffer. */
    _mirrorTexture = &_hmd->createMirrorTexture(TextureFormat::RGBA, resolution);
    _mirrorFramebuffer.reset(new Framebuffer(Range2Di::fromSize({}, resolution)));
    _mirrorFramebuffer->attachTexture(Framebuffer::ColorAttachment(0), *_mirrorTexture, 0)
                      .mapForRead(Framebuffer::ColorAttachment(0));

    /* Setup cube mesh. */
    const Trade::MeshData3D cube = Primitives::Cube::solid();

    _vertexBuffer.reset(new Buffer());
    _vertexBuffer->setData(
                MeshTools::interleave(cube.positions(0), cube.normals(0)),
                BufferUsage::StaticDraw);

    Containers::Array<char> indexData;
    Mesh::IndexType indexType;
    UnsignedInt indexStart, indexEnd;
    std::tie(indexData, indexType, indexStart, indexEnd) =
            MeshTools::compressIndices(cube.indices());

    _indexBuffer.reset(new Buffer());
    _indexBuffer->setData(indexData, BufferUsage::StaticDraw);

    _mesh.reset(new Mesh());
    _mesh->setPrimitive(cube.primitive()).setCount(cube.indices().size()).addVertexBuffer(
                *_vertexBuffer, 0, Shaders::Phong::Position {},
                Shaders::Phong::Normal {}).setIndexBuffer(*_indexBuffer, 0, indexType,
                                                          indexStart, indexEnd);

    /* setup shader */
    _shader.reset(new Shaders::Phong());

    /* setup scene */
    _cubes[0] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[0]->rotateY(Deg(45.0f));
    _cubes[0]->translate({0.0f, 0.0f, -3.0f});
    _cubeDrawables[0] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {1.0f, 1.0f, 0.0f}, _cubes[0].get(), &_drawables));

    _cubes[1] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[1]->rotateY(Deg(45.0f));
    _cubes[1]->translate({5.0f, 0.0f, 0.0f});
    _cubeDrawables[1] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {1.0f, 0.0f, 0.0f}, _cubes[1].get(), &_drawables));

    _cubes[2] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[2]->rotateY(Deg(45.0f));
    _cubes[2]->translate({-10.0f, 0.0f, 0.0f});
    _cubeDrawables[2] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {0.0f, 0.0f, 1.0f}, _cubes[2].get(), &_drawables));

    _cubes[3] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[3]->rotateY(Deg(45.0f));
    _cubes[3]->translate({0.0f, 0.0f, 7.0f});
    _cubeDrawables[3] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {0.0f, 1.0f, 1.0f}, _cubes[3].get(), &_drawables));

    /* setup compositor layers */
    _layer = &LibOvrIntegration::Context::get().compositor().addLayerEyeFov();
    _layer->setFov(*_hmd.get());
    _layer->setHighQuality(true);

    /* setup cameras */
    _eyes[0].setParent(&_cameraObject);
    _eyes[1].setParent(&_cameraObject);

    for(int eye = 0; eye < 2; ++eye) {
        /* projection matrix is set in the camera, since it requires some hmd-specific fov etc. */
        _cameras[eye].reset(new HmdCamera(*_hmd, eye, _eyes[eye]));

        _layer->setColorTexture(eye, _cameras[eye]->textureSet());
        _layer->setViewport(eye, {{}, _cameras[eye]->viewport()});
    }

}

OvrExample::~OvrExample() {
}

void OvrExample::drawEvent() {
    /* get orientation and position of the hmd. */
    std::array<DualQuaternion, 2> poses = _hmd->pollEyePoses().eyePoses();

    /* draw the scene for both cameras */
    for(int eye = 0; eye < 2; ++eye) {
        /* set the transformation according to rift trackers */
        _eyes[eye].setTransformation(poses[eye].toMatrix());
        /* render each eye. */
        _cameras[eye]->draw(_drawables);
    }

    /* set the layers eye poses to the poses chached in the _hmd. */
    _layer->setRenderPoses(*_hmd.get());

    /* let the libOVR sdk compositor do its magic! */
    LibOvrIntegration::Context::get().compositor().submitFrame(*_hmd.get());

    /* blit mirror texture to defaultFramebuffer. */
    const Vector2i size = _mirrorTexture->imageSize(0);
    Framebuffer::blit(*_mirrorFramebuffer,
                      defaultFramebuffer,
                      {{0, size.y()}, {size.x(), 0}},
                      {{}, size},
                      FramebufferBlit::Color, FramebufferBlitFilter::Nearest);

    if(_hmd->isDebugHmd()) {
        /* provide some rotation, but only without real devices to avoid vr sickness ;) */
        _cameraObject.rotateY(Deg(0.1f));
    }

    swapBuffers();
    redraw();
}

void OvrExample::keyPressEvent(KeyEvent& event) {
    if(event.key() == KeyEvent::Key::F11) {
        /* toggle through the performance hud modes */
        switch(_curPerfHudMode) {
            case PerformanceHudMode::Off:
                _curPerfHudMode = PerformanceHudMode::LatencyTiming;
                break;
            case PerformanceHudMode::LatencyTiming:
                _curPerfHudMode = PerformanceHudMode::RenderTiming;
                break;
            case PerformanceHudMode::RenderTiming:
                _curPerfHudMode = PerformanceHudMode::Off;
                break;
        }

        /** libovr has a bug where performance hud will block the app when using a debug hmd */
        if(!_hmd->isDebugHmd()) {
            _hmd->setPerformanceHudMode(_curPerfHudMode);
        }
    } else if(event.key() == KeyEvent::Key::Esc) {
        exit();
    }
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::OvrExample)
<|endoftext|>


<commit_before>#include <snn/network.h>

namespace snn {

    network::network(int N)
        : m_N(N)
        , m_Ne(N * 0.8)
        , m_Ni(m_N - m_Ne)
        , m_a(N)
        , m_b(N)
        , m_c(N)
        , m_d(N)
        , m_s(N, N)
        , m_v(N)
        , m_u(N)
        , m_I(N)
        , m_fired(N)
    {
        // initialize vector a
        for (int i = 0; i < m_Ne; ++ i)
            m_a[i] = 0.02;
        for (int i = m_Ne; i < m_N; ++ i)
            m_a[i] = 0.1;

        // initialize vector b
        for (int i = 0; i < m_N; ++ i)
            m_b[i] = 0.2;

        // initialize vector c
        for (int i = 0; i < m_N; ++ i)
            m_c[i] = -65.0;

        // initialize vector d
        for (int i = 0; i < m_Ne; ++ i)
            m_d[i] = 8.0;
        for (int i = m_Ne; i < m_N; ++ i)
            m_d[i] = 2.0;

        // initialize matrix of synaptic strength
        for (int i = 0; i < m_N; ++ i)
        {
            for (int j = 0; j < m_Ne; ++ j)
                m_s(i, j) = 0.25;
            for (int j = m_Ne; j < m_N; ++ j)
                m_s(i, j) = -0.5;
        }

        // initialize vectors v and u
        m_v = m_c;
        m_u = m_b % m_v;

        // reserved memory for firings
        m_fired.reserve(m_N);
    }

    void network::generate_random_input()
    {
        std::uniform_real_distribution<double> dist(-6.5, 6.5);
        for (int i = 0; i < m_N; ++ i)
            m_I[i] = dist(m_random_engine);
    }

    void network::process_firings()
    {
        m_fired.clear();

        // detect fired neurons
        for (int i = 0; i < m_N; ++ i)
            if (m_v[i] >= 30.0)
                m_fired.push_back(i);

        // reset potential of fired neurons
        for (int i, n = m_fired.size(); i < n; ++ i)
        {
            const int index = m_fired[i];
            m_v[index] = m_c[index];
            m_u[index] += m_d[index];
        }

        // update input current
        if (!m_fired.empty())
            for (int i = 0; i < m_N; ++ i)
            {
                double neuron_I = 0.0;
                for (int j = 0, n = m_fired.size(); j < n; ++ j)
                    neuron_I += m_s.at(i, m_fired[j]);
                m_I[i] += neuron_I;
            }
    }

    void network::update_potentials()
    {
        m_v += ((0.04 * m_v + 5.0) % m_v + 140.0 - m_u + m_I);
        m_u += (m_a % (m_b % m_v - m_u));
    }

} // namespace snn
<commit_msg>use half millisecond step<commit_after>#include <snn/network.h>

namespace snn {

    network::network(int N)
        : m_N(N)
        , m_Ne(N * 0.8)
        , m_Ni(m_N - m_Ne)
        , m_a(N)
        , m_b(N)
        , m_c(N)
        , m_d(N)
        , m_s(N, N)
        , m_v(N)
        , m_u(N)
        , m_I(N)
        , m_fired(N)
    {
        // initialize vector a
        for (int i = 0; i < m_Ne; ++ i)
            m_a[i] = 0.02;
        for (int i = m_Ne; i < m_N; ++ i)
            m_a[i] = 0.1;

        // initialize vector b
        for (int i = 0; i < m_N; ++ i)
            m_b[i] = 0.2;

        // initialize vector c
        for (int i = 0; i < m_N; ++ i)
            m_c[i] = -65.0;

        // initialize vector d
        for (int i = 0; i < m_Ne; ++ i)
            m_d[i] = 8.0;
        for (int i = m_Ne; i < m_N; ++ i)
            m_d[i] = 2.0;

        // initialize matrix of synaptic strength
        for (int i = 0; i < m_N; ++ i)
        {
            for (int j = 0; j < m_Ne; ++ j)
                m_s(i, j) = 0.25;
            for (int j = m_Ne; j < m_N; ++ j)
                m_s(i, j) = -0.5;
        }

        // initialize vectors v and u
        m_v = m_c;
        m_u = m_b % m_v;

        // reserved memory for firings
        m_fired.reserve(m_N);
    }

    void network::generate_random_input()
    {
        std::uniform_real_distribution<double> dist(-6.5, 6.5);
        for (int i = 0; i < m_N; ++ i)
            m_I[i] = dist(m_random_engine);
    }

    void network::process_firings()
    {
        m_fired.clear();

        // detect fired neurons
        for (int i = 0; i < m_N; ++ i)
            if (m_v[i] >= 30.0)
                m_fired.push_back(i);

        // reset potential of fired neurons
        for (int i, n = m_fired.size(); i < n; ++ i)
        {
            const int index = m_fired[i];
            m_v[index] = m_c[index];
            m_u[index] += m_d[index];
        }

        // update input current
        if (!m_fired.empty())
            for (int i = 0; i < m_N; ++ i)
            {
                double neuron_I = 0.0;
                for (int j = 0, n = m_fired.size(); j < n; ++ j)
                    neuron_I += m_s.at(i, m_fired[j]);
                m_I[i] += neuron_I;
            }
    }

    void network::update_potentials()
    {
        for (int i = 0; i < 2; ++ i)
            m_v += 0.5 * ((0.04 * m_v + 5.0) % m_v + 140.0 - m_u + m_I);
        m_u += (m_a % (m_b % m_v - m_u));
    }

} // namespace snn
<|endoftext|>


<commit_before>
#ifdef JASP_R_INTERFACE_LIBRARY
#include "jasprcpp.h"
#else
bool jaspRCPP_setColumnDataAsScale(			std::string, Rcpp::RObject) { jaspPrint("jaspColumn does nothing in R stand-alone!"); return false; };
bool jaspRCPP_setColumnDataAsOrdinal(		std::string, Rcpp::RObject) { jaspPrint("jaspColumn does nothing in R stand-alone!"); return false; };
bool jaspRCPP_setColumnDataAsNominal(		std::string, Rcpp::RObject) { jaspPrint("jaspColumn does nothing in R stand-alone!"); return false; };
bool jaspRCPP_setColumnDataAsNominalText(	std::string, Rcpp::RObject) { jaspPrint("jaspColumn does nothing in R stand-alone!"); return false; };
#endif

#include "jaspColumn.h"

Json::Value jaspColumn::convertToJSON()
{
	Json::Value obj		= jaspObject::convertToJSON();

	obj["columnName"]	= _columnName;
	obj["columnType"]	= jaspColumnTypeToString(_columnType);

	return obj;
}

void jaspColumn::convertFromJSON_SetFields(Json::Value in)
{
	jaspObject::convertFromJSON_SetFields(in);

	_columnName = in["columnName"].asString();
	_columnType	= jaspColumnTypeFromString(in["columnType"].asString());
	_changed	= false;
}

std::string jaspColumn::dataToString(std::string prefix)
{
	std::stringstream out;

	out << prefix << "column " << _columnName << " has type " << jaspColumnTypeToString(_columnType) << " and had " << (_changed? "" : "no ") << "changes!\n";

	return out.str();
}

void jaspColumn::setScale(Rcpp::RObject scalarData)
{
	_changed	= jaspRCPP_setColumnDataAsScale(_columnName, scalarData);//		|| _columnType != jaspColumnType::scale;
	_columnType = jaspColumnType::scale;

	if(_changed) notifyParentOfChanges();

}

void jaspColumn::setOrdinal(Rcpp::RObject ordinalData)
{
	_changed	= jaspRCPP_setColumnDataAsOrdinal(_columnName, ordinalData);//	|| _columnType != jaspColumnType::ordinal;
	_columnType = jaspColumnType::ordinal;

	if(_changed) notifyParentOfChanges();
}

void jaspColumn::setNominal(Rcpp::RObject nominalData)
{
	_changed	= jaspRCPP_setColumnDataAsNominal(_columnName, nominalData);//	|| _columnType != jaspColumnType::nominal;
	_columnType = jaspColumnType::nominal;

	if(_changed) notifyParentOfChanges();
}

void jaspColumn::setNominalText(Rcpp::RObject nominalData)
{
	_changed	= jaspRCPP_setColumnDataAsNominalText(_columnName, nominalData);//	|| _columnType != jaspColumnType::text;
	_columnType = jaspColumnType::text;

	if(_changed) notifyParentOfChanges();
}

Json::Value jaspColumn::dataEntry()
{
	Json::Value data(jaspObject::dataEntry());

	data["columnName"]	= _columnName;
	data["columnType"]	= jaspColumnTypeToString(_columnType);
	data["dataChanged"]	= _changed;

	return data;
}
<commit_msg>Fixes https://github.com/jasp-stats/INTERNAL-jasp/issues/326 (Cannot build jaspResults for jaspTools)<commit_after>
#include "jaspColumn.h"

#ifdef JASP_R_INTERFACE_LIBRARY
#include "jasprcpp.h"
#else
bool jaspRCPP_setColumnDataAsScale(			std::string, Rcpp::RObject) { jaspPrint("jaspColumn does nothing in R stand-alone!"); return false; };
bool jaspRCPP_setColumnDataAsOrdinal(		std::string, Rcpp::RObject) { jaspPrint("jaspColumn does nothing in R stand-alone!"); return false; };
bool jaspRCPP_setColumnDataAsNominal(		std::string, Rcpp::RObject) { jaspPrint("jaspColumn does nothing in R stand-alone!"); return false; };
bool jaspRCPP_setColumnDataAsNominalText(	std::string, Rcpp::RObject) { jaspPrint("jaspColumn does nothing in R stand-alone!"); return false; };
#endif

Json::Value jaspColumn::convertToJSON()
{
	Json::Value obj		= jaspObject::convertToJSON();

	obj["columnName"]	= _columnName;
	obj["columnType"]	= jaspColumnTypeToString(_columnType);

	return obj;
}

void jaspColumn::convertFromJSON_SetFields(Json::Value in)
{
	jaspObject::convertFromJSON_SetFields(in);

	_columnName = in["columnName"].asString();
	_columnType	= jaspColumnTypeFromString(in["columnType"].asString());
	_changed	= false;
}

std::string jaspColumn::dataToString(std::string prefix)
{
	std::stringstream out;

	out << prefix << "column " << _columnName << " has type " << jaspColumnTypeToString(_columnType) << " and had " << (_changed? "" : "no ") << "changes!\n";

	return out.str();
}

void jaspColumn::setScale(Rcpp::RObject scalarData)
{
	_changed	= jaspRCPP_setColumnDataAsScale(_columnName, scalarData);//		|| _columnType != jaspColumnType::scale;
	_columnType = jaspColumnType::scale;

	if(_changed) notifyParentOfChanges();

}

void jaspColumn::setOrdinal(Rcpp::RObject ordinalData)
{
	_changed	= jaspRCPP_setColumnDataAsOrdinal(_columnName, ordinalData);//	|| _columnType != jaspColumnType::ordinal;
	_columnType = jaspColumnType::ordinal;

	if(_changed) notifyParentOfChanges();
}

void jaspColumn::setNominal(Rcpp::RObject nominalData)
{
	_changed	= jaspRCPP_setColumnDataAsNominal(_columnName, nominalData);//	|| _columnType != jaspColumnType::nominal;
	_columnType = jaspColumnType::nominal;

	if(_changed) notifyParentOfChanges();
}

void jaspColumn::setNominalText(Rcpp::RObject nominalData)
{
	_changed	= jaspRCPP_setColumnDataAsNominalText(_columnName, nominalData);//	|| _columnType != jaspColumnType::text;
	_columnType = jaspColumnType::text;

	if(_changed) notifyParentOfChanges();
}

Json::Value jaspColumn::dataEntry()
{
	Json::Value data(jaspObject::dataEntry());

	data["columnName"]	= _columnName;
	data["columnType"]	= jaspColumnTypeToString(_columnType);
	data["dataChanged"]	= _changed;

	return data;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS.  All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.

#include <windows.h>
#include <windowsx.h>
#include <comdef.h>
#include <comip.h>
#include <shlwapi.h>

#include <cassert>
#include <string>

#include "debugutil.hpp"
#include "hrtext.hpp"
#include "ComDllWrapper.hpp"

namespace WebmMfUtil
{

ComDllWrapper::ComDllWrapper():
  dll_module_(NULL),
  clsid_(GUID_NULL),
  ptrfn_get_class_object_(NULL),
  ref_count_(0)
{
}

ComDllWrapper::~ComDllWrapper()
{
    if (ptr_class_factory_)
    {
        //ptr_class_factory_->LockServer(FALSE);
        ptr_class_factory_ = 0;
    }
    if (NULL != dll_module_)
    {
        FreeLibrary(dll_module_);
        dll_module_ = NULL;
    }
}

UINT ComDllWrapper::AddRef()
{
    return InterlockedIncrement(&ref_count_);
}

UINT ComDllWrapper::Release()
{
    UINT ref_count = InterlockedDecrement(&ref_count_);
    if (0 == ref_count)
    {
        delete this;
    }
    return ref_count;
}

HRESULT ComDllWrapper::Create(std::wstring dll_path, CLSID clsid,
                              ComDllWrapper** ptr_instance)
{
    if (!PathFileExists(dll_path.c_str()))
        return E_INVALIDARG;

    ComDllWrapper* ptr_wrapper = new (std::nothrow) ComDllWrapper();

    if (NULL == ptr_wrapper)
    {
        DBGLOG("ctor failed");
        return E_OUTOFMEMORY;
    }

    ptr_wrapper->dll_path_ = dll_path;
    ptr_wrapper->clsid_ = clsid;

    HRESULT hr = ptr_wrapper->LoadDll_();

    if (FAILED(hr))
    {
        DBGLOG("LoadDll_ failed");
        return hr;
    }
    ptr_wrapper->AddRef();
    *ptr_instance = ptr_wrapper;
    return hr;
}

HRESULT ComDllWrapper::LoadDll_()
{
    dll_module_ = LoadLibrary(dll_path_.c_str());
    if (dll_module_)
    {
        ptrfn_get_class_object_ = reinterpret_cast<DllGetClassObjFunc>(
            GetProcAddress(dll_module_, "DllGetClassObject"));
    }
    HRESULT hr = E_FAIL;
    if (dll_module_ && ptrfn_get_class_object_)
    {
        hr = ptrfn_get_class_object_(clsid_, IID_IClassFactory,
            reinterpret_cast<void**>(&ptr_class_factory_));
        if (FAILED(hr))
        {
            DBGLOG("DllGetClassObject failed" << HRLOG(hr));
        }
        if (SUCCEEDED(hr) && ptr_class_factory_)
        {
            //hr = ptr_class_factory_->LockServer(TRUE);
            //if (FAILED(hr))
            //{
            //    DBGLOG("LockServer failed" << HRTEXT(hr));
            //    return hr;
            //}
        }
    }
    return hr;
}

IClassFactoryPtr ComDllWrapper::GetIClassFactoryPtr() const
{
    return ptr_class_factory_;
}

HRESULT ComDllWrapper::CreateInstance(GUID interface_id, void** ptr_instance)
{
    if (!ptr_class_factory_)
    {
        return E_INVALIDARG;
    }
    return ptr_class_factory_->CreateInstance(NULL, interface_id,
                                              ptr_instance);
}

const wchar_t* ComDllWrapper::GetDllPath() const
{
    return dll_path_.c_str();
}

const CLSID ComDllWrapper::GetClsid() const
{
    return clsid_;
}

} // WebmMfUtil namespace<commit_msg>comdllwrapper: LockServer<commit_after>// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS.  All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.

#include <windows.h>
#include <windowsx.h>
#include <comdef.h>
#include <comip.h>
#include <shlwapi.h>

#include <cassert>
#include <string>

#include "debugutil.hpp"
#include "hrtext.hpp"
#include "ComDllWrapper.hpp"

namespace WebmMfUtil
{

ComDllWrapper::ComDllWrapper():
  dll_module_(NULL),
  clsid_(GUID_NULL),
  ptrfn_get_class_object_(NULL),
  ref_count_(0)
{
}

ComDllWrapper::~ComDllWrapper()
{
    if (ptr_class_factory_)
    {
        IClassFactory* ptr_class_factory = ptr_class_factory_.Detach();
        ptr_class_factory->LockServer(FALSE);
    }
    if (NULL != dll_module_)
    {
        FreeLibrary(dll_module_);
        dll_module_ = NULL;
    }
}

UINT ComDllWrapper::AddRef()
{
    return InterlockedIncrement(&ref_count_);
}

UINT ComDllWrapper::Release()
{
    UINT ref_count = InterlockedDecrement(&ref_count_);
    if (0 == ref_count)
    {
        delete this;
    }
    return ref_count;
}

HRESULT ComDllWrapper::Create(std::wstring dll_path, CLSID clsid,
                              ComDllWrapper** ptr_instance)
{
    if (!PathFileExists(dll_path.c_str()))
        return E_INVALIDARG;

    ComDllWrapper* ptr_wrapper = new (std::nothrow) ComDllWrapper();

    if (NULL == ptr_wrapper)
    {
        DBGLOG("ctor failed");
        return E_OUTOFMEMORY;
    }

    ptr_wrapper->dll_path_ = dll_path;
    ptr_wrapper->clsid_ = clsid;

    HRESULT hr = ptr_wrapper->LoadDll_();

    if (FAILED(hr))
    {
        DBGLOG("LoadDll_ failed");
        return hr;
    }
    ptr_wrapper->AddRef();
    *ptr_instance = ptr_wrapper;
    return hr;
}

HRESULT ComDllWrapper::LoadDll_()
{
    dll_module_ = LoadLibrary(dll_path_.c_str());
    if (dll_module_)
    {
        ptrfn_get_class_object_ = reinterpret_cast<DllGetClassObjFunc>(
            GetProcAddress(dll_module_, "DllGetClassObject"));
    }
    HRESULT hr = E_FAIL;
    if (dll_module_ && ptrfn_get_class_object_)
    {
        hr = ptrfn_get_class_object_(clsid_, IID_IClassFactory,
            reinterpret_cast<void**>(&ptr_class_factory_));
        if (FAILED(hr))
        {
            DBGLOG("DllGetClassObject failed" << HRLOG(hr));
        }
        if (SUCCEEDED(hr) && ptr_class_factory_)
        {
            hr = ptr_class_factory_->LockServer(TRUE);
            if (FAILED(hr))
            {
                DBGLOG("LockServer failed" << HRLOG(hr));
                return hr;
            }
        }
    }
    return hr;
}

IClassFactoryPtr ComDllWrapper::GetIClassFactoryPtr() const
{
    return ptr_class_factory_;
}

HRESULT ComDllWrapper::CreateInstance(GUID interface_id, void** ptr_instance)
{
    if (!ptr_class_factory_)
    {
        return E_INVALIDARG;
    }
    return ptr_class_factory_->CreateInstance(NULL, interface_id,
                                              ptr_instance);
}

const wchar_t* ComDllWrapper::GetDllPath() const
{
    return dll_path_.c_str();
}

const CLSID ComDllWrapper::GetClsid() const
{
    return clsid_;
}

} // WebmMfUtil namespace<|endoftext|>


<commit_before>#include <cc1101.hpp>

template <typename cc1101>
class Radio : public cc1101 {
	static void setup_common();
public:
	static void setup_for_rx();
	static void setup_for_tx();
};

template <typename cc1101>
inline void Radio<cc1101>::setup_common()
{
	// reset
	cc1101::select();
	cc1101::template wcmd<CC1101::SRES>();
	cc1101::release();

	cc1101::select();

	// disable GDO[0,2] pins
	cc1101::template set<CC1101::IOCFG2>(0x2f);
	cc1101::template set<CC1101::IOCFG0>(0x2f);

	// fix packet length
	cc1101::template set<CC1101::PKTLEN>(16);

	// packet automation
	cc1101::template set<CC1101::PKTCTRL0>(0x44);

	// frequency configuration
	cc1101::template set<CC1101::FREQ2>(0x10);
	cc1101::template set<CC1101::FREQ1>(0xa7);
	cc1101::template set<CC1101::FREQ0>(0xe1);

	// modem configuration
	cc1101::template set<CC1101::MDMCFG2>(0x16);
	cc1101::template set<CC1101::MDMCFG1>(0xa2);

	// calibrate
	cc1101::template wcmd<CC1101::SCAL>();
	while ((cc1101::template status<CC1101::MARCSTATE>() & 0x1f) != 1)
		;
}

template <typename cc1101>
inline void Radio<cc1101>::setup_for_rx()
{
	setup_common();

	// packet automation
	cc1101::template set<CC1101::PKTCTRL1>(0x2c);

	// main radio control state machine configuration
	cc1101::template set<CC1101::MCSM1>(0x3c);
	cc1101::template set<CC1101::MCSM0>(0x34);

	cc1101::release();
}

template <typename cc1101>
inline void Radio<cc1101>::setup_for_tx()
{
	setup_common();

	// main radio control state machine configuration
	cc1101::template set<CC1101::MCSM0>(0x38);

	// PATABLE
	cc1101::template set<CC1101::PATABLE>(0x60);

	cc1101::release();
}
<commit_msg>RF: sensor TX power increased to 12 dBm<commit_after>#include <cc1101.hpp>

template <typename cc1101>
class Radio : public cc1101 {
	static void setup_common();
public:
	static void setup_for_rx();
	static void setup_for_tx();
};

template <typename cc1101>
inline void Radio<cc1101>::setup_common()
{
	// reset
	cc1101::select();
	cc1101::template wcmd<CC1101::SRES>();
	cc1101::release();

	cc1101::select();

	// disable GDO[0,2] pins
	cc1101::template set<CC1101::IOCFG2>(0x2f);
	cc1101::template set<CC1101::IOCFG0>(0x2f);

	// fix packet length
	cc1101::template set<CC1101::PKTLEN>(16);

	// packet automation
	cc1101::template set<CC1101::PKTCTRL0>(0x44);

	// frequency configuration
	cc1101::template set<CC1101::FREQ2>(0x10);
	cc1101::template set<CC1101::FREQ1>(0xa7);
	cc1101::template set<CC1101::FREQ0>(0xe1);

	// modem configuration
	cc1101::template set<CC1101::MDMCFG2>(0x16);
	cc1101::template set<CC1101::MDMCFG1>(0xa2);

	// calibrate
	cc1101::template wcmd<CC1101::SCAL>();
	while ((cc1101::template status<CC1101::MARCSTATE>() & 0x1f) != 1)
		;
}

template <typename cc1101>
inline void Radio<cc1101>::setup_for_rx()
{
	setup_common();

	// packet automation
	cc1101::template set<CC1101::PKTCTRL1>(0x2c);

	// main radio control state machine configuration
	cc1101::template set<CC1101::MCSM1>(0x3c);
	cc1101::template set<CC1101::MCSM0>(0x34);

	cc1101::release();
}

template <typename cc1101>
inline void Radio<cc1101>::setup_for_tx()
{
	setup_common();

	// main radio control state machine configuration
	cc1101::template set<CC1101::MCSM0>(0x38);

	// PATABLE
	cc1101::template set<CC1101::PATABLE>(0xc0);

	cc1101::release();
}
<|endoftext|>


<commit_before>#include <cc1101.hpp>

template <typename cc1101>
class Radio : public cc1101 {
	static void setup_common();
public:
	static void setup_for_rx();
	static void setup_for_tx();
};

template <typename cc1101>
inline void Radio<cc1101>::setup_common()
{
	// reset
	cc1101::select();
	cc1101::wcmd(CC1101::SRES);
	cc1101::release();

	cc1101::select();

	// disable GDO[0,2] pins
	cc1101::set(CC1101::IOCFG2, 0x2f);
	cc1101::set(CC1101::IOCFG0, 0x2f);

	// fix packet length
	cc1101::set(CC1101::PKTLEN, 16);

	// packet automation
	cc1101::set(CC1101::PKTCTRL0, 0x44);

	// frequency configuration
	cc1101::set(CC1101::FREQ2, 0x10);
	cc1101::set(CC1101::FREQ1, 0xa7);
	cc1101::set(CC1101::FREQ0, 0xe1);

	// modem configuration
	cc1101::set(CC1101::MDMCFG4, 0x6a);
	cc1101::set(CC1101::MDMCFG3, 0x83);
	cc1101::set(CC1101::MDMCFG2, 0x13);

	// calibrate
	cc1101::wcmd(CC1101::SCAL);
	while ((cc1101::status(CC1101::MARCSTATE) & 0x1f) != 1)
		;
}

template <typename cc1101>
inline void Radio<cc1101>::setup_for_rx()
{
	setup_common();

	// packet automation
	cc1101::set(CC1101::PKTCTRL1, 0x2c);

	// main radio control state machine configuration
	cc1101::set(CC1101::MCSM1, 0x3c);
	cc1101::set(CC1101::MCSM0, 0x34);

	cc1101::release();
}

template <typename cc1101>
inline void Radio<cc1101>::setup_for_tx()
{
	setup_common();

	// main radio control state machine configuration
	cc1101::set(CC1101::MCSM0, 0x38);

	// PATABLE
	cc1101::set(CC1101::PATABLE, 0xc0);

	cc1101::release();
}
<commit_msg>radio tuned<commit_after>#include <cc1101.hpp>

template <typename cc1101>
class Radio : public cc1101 {
	static void setup_common();
public:
	static void setup_for_rx();
	static void setup_for_tx();
};

template <typename cc1101>
inline void Radio<cc1101>::setup_common()
{
	// reset
	cc1101::select();
	cc1101::wcmd(CC1101::SRES);
	cc1101::release();

	cc1101::select();

	// disable GDO[0,2] pins
	cc1101::set(CC1101::IOCFG2, 0x2f);
	cc1101::set(CC1101::IOCFG0, 0x2f);

	// fix packet length
	cc1101::set(CC1101::PKTLEN, 16);

	// packet automation
	cc1101::set(CC1101::PKTCTRL0, 0x44);

	// frequency configuration
	cc1101::set(CC1101::FREQ2, 0x10);
	cc1101::set(CC1101::FREQ1, 0xa7);
	cc1101::set(CC1101::FREQ0, 0xe1);

	// modem configuration
	cc1101::set(CC1101::MDMCFG4, 0x3c);
	cc1101::set(CC1101::MDMCFG3, 0x24);
	cc1101::set(CC1101::MDMCFG2, 0x13);
	cc1101::set(CC1101::DEVIATN, 0x53);

	// calibrate
	cc1101::wcmd(CC1101::SCAL);
	while ((cc1101::status(CC1101::MARCSTATE) & 0x1f) != 1)
		;
}

template <typename cc1101>
inline void Radio<cc1101>::setup_for_rx()
{
	setup_common();

	// packet automation
	cc1101::set(CC1101::PKTCTRL1, 0x2c);

	// main radio control state machine configuration
	cc1101::set(CC1101::MCSM1, 0x3c);
	cc1101::set(CC1101::MCSM0, 0x34);

	cc1101::release();
}

template <typename cc1101>
inline void Radio<cc1101>::setup_for_tx()
{
	setup_common();

	// main radio control state machine configuration
	cc1101::set(CC1101::MCSM0, 0x38);

	// PATABLE
	cc1101::set(CC1101::PATABLE, 0xc0);

	cc1101::release();
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Sergey Zolotarev
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cstddef>
#include <map>

#include "jit.h"
#include "jump-x86.h"
#include "plugin.h"
#include "pluginversion.h"

using namespace jit;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, JIT*> JITMap;
static JITMap jit_map;

static JIT *GetJIT(AMX *amx) {
	JITMap::const_iterator it = jit_map.find(amx);
	if (it == jit_map.end()) {
		JIT *jit = new JIT(amx);
		jit_map.insert(std::make_pair(amx, jit));
		return jit;
	} else {
		return it->second;
	}
}

static void DeleteJIT(AMX *amx) {
	JITMap::iterator it = jit_map.find(amx);
	if (it != jit_map.end()) {
		delete it->second;
		jit_map.erase(it);
	}
}

// This implementation of amx_GetAddr can accept ANY amx_addr, even out of the data section.
static int AMXAPI amx_GetAddr_JIT(AMX *amx, cell amx_addr, cell **phys_addr) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	*phys_addr = reinterpret_cast<cell*>(amx->base + hdr->dat + amx_addr);
	return AMX_ERR_NONE;
}

// amx_Exec_JIT compiles a public function (if needed) and runs the generated JIT code.
static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
	if (index != AMX_EXEC_CONT) {
		return GetJIT(amx)->CallPublicFunction(index, retval);
	}
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];

	new JumpX86(((void**)ppData[PLUGIN_DATA_AMX_EXPORTS])[PLUGIN_AMX_EXPORT_Exec], (void*)amx_Exec_JIT);
	new JumpX86(((void**)ppData[PLUGIN_DATA_AMX_EXPORTS])[PLUGIN_AMX_EXPORT_GetAddr], (void*)amx_GetAddr_JIT);

	logprintf("  JIT plugin v%s is OK.", PLUGIN_VERSION_STRING);

	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	// nothing
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	DeleteJIT(amx);
	return AMX_ERR_NONE;
}
<commit_msg>Delete unnecessary comments<commit_after>// Copyright (c) 2012, Sergey Zolotarev
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cstddef>
#include <map>

#include "jit.h"
#include "jump-x86.h"
#include "plugin.h"
#include "pluginversion.h"

using namespace jit;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, JIT*> JITMap;
static JITMap jit_map;

static JIT *GetJIT(AMX *amx) {
	JITMap::const_iterator it = jit_map.find(amx);
	if (it == jit_map.end()) {
		JIT *jit = new JIT(amx);
		jit_map.insert(std::make_pair(amx, jit));
		return jit;
	} else {
		return it->second;
	}
}

static void DeleteJIT(AMX *amx) {
	JITMap::iterator it = jit_map.find(amx);
	if (it != jit_map.end()) {
		delete it->second;
		jit_map.erase(it);
	}
}

static int AMXAPI amx_GetAddr_JIT(AMX *amx, cell amx_addr, cell **phys_addr) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	*phys_addr = reinterpret_cast<cell*>(amx->base + hdr->dat + amx_addr);
	return AMX_ERR_NONE;
}

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
	if (index != AMX_EXEC_CONT) {
		return GetJIT(amx)->CallPublicFunction(index, retval);
	}
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];

	new JumpX86(((void**)ppData[PLUGIN_DATA_AMX_EXPORTS])[PLUGIN_AMX_EXPORT_Exec], (void*)amx_Exec_JIT);
	new JumpX86(((void**)ppData[PLUGIN_DATA_AMX_EXPORTS])[PLUGIN_AMX_EXPORT_GetAddr], (void*)amx_GetAddr_JIT);

	logprintf("  JIT plugin v%s is OK.", PLUGIN_VERSION_STRING);

	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	// nothing
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	DeleteJIT(amx);
	return AMX_ERR_NONE;
}
<|endoftext|>


<commit_before>//
//  HUDQuadWidget.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 12/17/13.
//
//

#include "HUDQuadWidget.hpp"

#include "Context.hpp"
#include "IDownloader.hpp"
#include "IImageDownloadListener.hpp"
#include "TexturesHandler.hpp"
#include "Camera.hpp"
#include "Vector3D.hpp"
#include "FloatBufferBuilderFromCartesian3D.hpp"
#include "FloatBufferBuilderFromCartesian2D.hpp"
#include "DirectMesh.hpp"
#include "TexturedMesh.hpp"

class HUDQuadWidget_ImageDownloadListener : public IImageDownloadListener {
  HUDQuadWidget* _quadWidget;

public:
  HUDQuadWidget_ImageDownloadListener(HUDQuadWidget* quadWidget) :
  _quadWidget(quadWidget)
  {
  }

  void onDownload(const URL& url,
                  IImage* image,
                  bool expired)  {
    _quadWidget->onImageDownload(image);
  }

  void onError(const URL& url) {
    _quadWidget->onImageDownloadError(url);
  }

  void onCancel(const URL& url) {
    // do nothing
  }

  void onCanceledDownload(const URL& url,
                          IImage* image,
                          bool expired) {
    // do nothing
  }

};

HUDQuadWidget::~HUDQuadWidget() {
  delete _image;
  delete _mesh;
}

void HUDQuadWidget::initialize(const G3MContext* context) {
  if (!_downloadingImage && (_image == NULL)) {
    _downloadingImage = true;
    IDownloader* downloader = context->getDownloader();
    downloader->requestImage(_imageURL,
                             1000000, // priority
                             TimeInterval::fromDays(30),
                             true, // readExpired
                             new HUDQuadWidget_ImageDownloadListener(this),
                             true);
  }
}

void HUDQuadWidget::onResizeViewportEvent(const G3MEventContext* ec,
                                          int width,
                                          int height) {
  delete _mesh;
  _mesh = NULL;
}

void HUDQuadWidget::onImageDownload(IImage* image) {
  _downloadingImage = false;
  _image = image;
}

void HUDQuadWidget::onImageDownloadError(const URL& url) {
  _errors.push_back("HUDQuadWidget: Error downloading \"" + url.getPath() + "\"");
}

RenderState HUDQuadWidget::getRenderState(const G3MRenderContext* rc) {
  if (!_errors.empty()) {
    return RenderState::error(_errors);
  }
  else if (_downloadingImage) {
    return RenderState::busy();
  }
  else {
    return RenderState::ready();
  }
}

Mesh* HUDQuadWidget::createMesh(const G3MRenderContext* rc) const {
  if (_image == NULL) {
    return NULL;
  }

//#ifdef C_CODE
//  const TextureIDReference* texId;
//#endif
//#ifdef JAVA_CODE
//  TextureIDReference texId;
//#endif

  const TextureIDReference* texId = rc->getTexturesHandler()->getTextureIDReference(_image,
                                                                                GLFormat::rgba(),
                                                                                _imageURL.getPath(),
                                                                                false);

  if (texId == NULL) {
    rc->getLogger()->logError("Can't upload texture to GPU");
    return NULL;
  }

  const Camera* camera = rc->getCurrentCamera();
  const int viewportWidth  = camera->getWidth();
  const int viewportHeight = camera->getHeight();

  const Vector3D halfViewportAndPosition(viewportWidth  / 2 - _x,
                                         viewportHeight / 2 - _y,
                                         0);

  const double w = _width;
  const double h = _height;

  FloatBufferBuilderFromCartesian3D* vertices = FloatBufferBuilderFromCartesian3D::builderWithoutCenter();
  vertices->add( Vector3D(0, h, 0).sub(halfViewportAndPosition) );
  vertices->add( Vector3D(0, 0, 0).sub(halfViewportAndPosition) );
  vertices->add( Vector3D(w, h, 0).sub(halfViewportAndPosition) );
  vertices->add( Vector3D(w, 0, 0).sub(halfViewportAndPosition) );

  FloatBufferBuilderFromCartesian2D texCoords;
  texCoords.add(0, 0);
  texCoords.add(0, 1);
  texCoords.add(1, 0);
  texCoords.add(1, 1);

  DirectMesh* dm = new DirectMesh(GLPrimitive::triangleStrip(),
                                  true,
                                  vertices->getCenter(),
                                  vertices->create(),
                                  1,
                                  1);

  delete vertices;

  TextureMapping* texMap = new SimpleTextureMapping(texId,
                                                    texCoords.create(),
                                                    true,
                                                    true);

  return new TexturedMesh(dm, true, texMap, true, true);
}

Mesh* HUDQuadWidget::getMesh(const G3MRenderContext* rc) {
  if (_mesh == NULL) {
    _mesh = createMesh(rc);
  }
  return _mesh;
}

void HUDQuadWidget::render(const G3MRenderContext* rc,
                           GLState* glState) {
  Mesh* mesh = getMesh(rc);
  if (mesh != NULL) {
    mesh->render(rc, glState);
  }
}
<commit_msg>slow progress - not yet usable<commit_after>//
//  HUDQuadWidget.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 12/17/13.
//
//

#include "HUDQuadWidget.hpp"

#include "Context.hpp"
#include "IDownloader.hpp"
#include "IImageDownloadListener.hpp"
#include "TexturesHandler.hpp"
#include "Camera.hpp"
#include "Vector3D.hpp"
#include "FloatBufferBuilderFromCartesian3D.hpp"
#include "FloatBufferBuilderFromCartesian2D.hpp"
#include "DirectMesh.hpp"
#include "TexturedMesh.hpp"

class HUDQuadWidget_ImageDownloadListener : public IImageDownloadListener {
private:
  HUDQuadWidget* _quadWidget;

public:
  HUDQuadWidget_ImageDownloadListener(HUDQuadWidget* quadWidget) :
  _quadWidget(quadWidget)
  {
  }

  void onDownload(const URL& url,
                  IImage* image,
                  bool expired)  {
    _quadWidget->onImageDownload(image);
  }

  void onError(const URL& url) {
    _quadWidget->onImageDownloadError(url);
  }

  void onCancel(const URL& url) {
    // do nothing
  }

  void onCanceledDownload(const URL& url,
                          IImage* image,
                          bool expired) {
    // do nothing
  }

};

HUDQuadWidget::~HUDQuadWidget() {
  delete _image;
  delete _mesh;
}

void HUDQuadWidget::initialize(const G3MContext* context) {
  if (!_downloadingImage && (_image == NULL)) {
    _downloadingImage = true;
    IDownloader* downloader = context->getDownloader();
    downloader->requestImage(_imageURL,
                             1000000, // priority
                             TimeInterval::fromDays(30),
                             true, // readExpired
                             new HUDQuadWidget_ImageDownloadListener(this),
                             true);
  }
}

void HUDQuadWidget::onResizeViewportEvent(const G3MEventContext* ec,
                                          int width,
                                          int height) {
  delete _mesh;
  _mesh = NULL;
}

void HUDQuadWidget::onImageDownload(IImage* image) {
  _downloadingImage = false;
  _image = image;
}

void HUDQuadWidget::onImageDownloadError(const URL& url) {
  _errors.push_back("HUDQuadWidget: Error downloading \"" + url.getPath() + "\"");
}

RenderState HUDQuadWidget::getRenderState(const G3MRenderContext* rc) {
  if (!_errors.empty()) {
    return RenderState::error(_errors);
  }
  else if (_downloadingImage) {
    return RenderState::busy();
  }
  else {
    return RenderState::ready();
  }
}

Mesh* HUDQuadWidget::createMesh(const G3MRenderContext* rc) const {
  if (_image == NULL) {
    return NULL;
  }

//#ifdef C_CODE
//  const TextureIDReference* texId;
//#endif
//#ifdef JAVA_CODE
//  TextureIDReference texId;
//#endif

  const TextureIDReference* texId = rc->getTexturesHandler()->getTextureIDReference(_image,
                                                                                GLFormat::rgba(),
                                                                                _imageURL.getPath(),
                                                                                false);

  if (texId == NULL) {
    rc->getLogger()->logError("Can't upload texture to GPU");
    return NULL;
  }

  const Camera* camera = rc->getCurrentCamera();
  const int viewportWidth  = camera->getWidth();
  const int viewportHeight = camera->getHeight();

  const Vector3D halfViewportAndPosition(viewportWidth  / 2 - _x,
                                         viewportHeight / 2 - _y,
                                         0);

  const double w = _width;
  const double h = _height;

  FloatBufferBuilderFromCartesian3D* vertices = FloatBufferBuilderFromCartesian3D::builderWithoutCenter();
  vertices->add( Vector3D(0, h, 0).sub(halfViewportAndPosition) );
  vertices->add( Vector3D(0, 0, 0).sub(halfViewportAndPosition) );
  vertices->add( Vector3D(w, h, 0).sub(halfViewportAndPosition) );
  vertices->add( Vector3D(w, 0, 0).sub(halfViewportAndPosition) );

  FloatBufferBuilderFromCartesian2D texCoords;
  texCoords.add(0, 0);
  texCoords.add(0, 1);
  texCoords.add(1, 0);
  texCoords.add(1, 1);

  DirectMesh* dm = new DirectMesh(GLPrimitive::triangleStrip(),
                                  true,
                                  vertices->getCenter(),
                                  vertices->create(),
                                  1,
                                  1);

  delete vertices;

  TextureMapping* texMap = new SimpleTextureMapping(texId,
                                                    texCoords.create(),
                                                    true,
                                                    true);

  return new TexturedMesh(dm, true, texMap, true, true);
}

Mesh* HUDQuadWidget::getMesh(const G3MRenderContext* rc) {
  if (_mesh == NULL) {
    _mesh = createMesh(rc);
  }
  return _mesh;
}

void HUDQuadWidget::render(const G3MRenderContext* rc,
                           GLState* glState) {
  Mesh* mesh = getMesh(rc);
  if (mesh != NULL) {
    mesh->render(rc, glState);
  }
}
<|endoftext|>