<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
/*=========================================================================
 *
 *  Portions of this file are subject to the VTK Toolkit Version 3 copyright.
 *
 *  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
 *
 *  For complete copyright, license and disclaimer of warranty information
 *  please refer to the NOTICE file at the top of the ITK source tree.
 *
 *=========================================================================*/
#include "itkMultiThreader.h"
#include "itkNumericTraits.h"
#include <iostream>
#include "vcl_algorithm.h"

#if defined(ITK_USE_PTHREADS)
#include "itkMultiThreaderPThreads.cxx"
#elif defined(ITK_USE_WIN32_THREADS)
#include "itkMultiThreaderWinThreads.cxx"
#else
#include "itkMultiThreaderNoThreads.cxx"
#endif

namespace itk
{

// GlobalDefaultUseThreadPoolIsInitialized is used only in this
// file to ensure that the ITK_USE_THREADPOOL environmenal variable
// is only used as a fall back option.  If the SetGlobalDefaultUseThreadPool
// API is ever used by the developer, the developers choice is
// respected over the environmental variable.
static bool GlobalDefaultUseThreadPoolIsInitialized=false;
static SimpleFastMutexLock globalDefaultInitializerLock;

bool MultiThreader::m_GlobalDefaultUseThreadPool = false;

void MultiThreader::SetGlobalDefaultUseThreadPool( const bool GlobalDefaultUseThreadPool )
  {
  m_GlobalDefaultUseThreadPool = GlobalDefaultUseThreadPool;
  GlobalDefaultUseThreadPoolIsInitialized=true;
  }

bool MultiThreader::GetGlobalDefaultUseThreadPool( )
  {
  if( ! GlobalDefaultUseThreadPoolIsInitialized )
    {
    //
    // look for runtime request to use thread pool
    std::string use_threadpool;
    if( itksys::SystemTools::GetEnv("ITK_USE_THREADPOOL",use_threadpool) )
      {
      MutexLockHolder< SimpleFastMutexLock > lock(globalDefaultInitializerLock);
      use_threadpool = itksys::SystemTools::UpperCase(use_threadpool);
      //NOTE: GlobalDefaultUseThreadPoolIsInitialized=true after this call
      if(use_threadpool != "NO" && use_threadpool != "OFF" && use_threadpool != "FALSE")
        {
        MultiThreader::SetGlobalDefaultUseThreadPool( true );
        }
      else
        {
        MultiThreader::SetGlobalDefaultUseThreadPool( false );
        }
      }
    }
  return m_GlobalDefaultUseThreadPool;
  }

// Initialize static member that controls global maximum number of threads.
ThreadIdType MultiThreader::m_GlobalMaximumNumberOfThreads = ITK_MAX_THREADS;

// Initialize static member that controls global default number of threads : 0
// => Not initialized.
ThreadIdType MultiThreader::m_GlobalDefaultNumberOfThreads = 0;

void MultiThreader::SetGlobalMaximumNumberOfThreads(ThreadIdType val)
{
  m_GlobalMaximumNumberOfThreads = val;

  // clamp between 1 and ITK_MAX_THREADS
  m_GlobalMaximumNumberOfThreads = vcl_min( m_GlobalMaximumNumberOfThreads,
                                             (ThreadIdType) ITK_MAX_THREADS );
  m_GlobalMaximumNumberOfThreads = vcl_max( m_GlobalMaximumNumberOfThreads,
                                             NumericTraits<ThreadIdType>::OneValue() );

  // If necessary reset the default to be used from now on.
  m_GlobalDefaultNumberOfThreads = vcl_min( m_GlobalDefaultNumberOfThreads,
                                             m_GlobalMaximumNumberOfThreads);
}

ThreadIdType MultiThreader::GetGlobalMaximumNumberOfThreads()
{
  return m_GlobalMaximumNumberOfThreads;
}

void MultiThreader::SetGlobalDefaultNumberOfThreads(ThreadIdType val)
{
  m_GlobalDefaultNumberOfThreads = val;

  // clamp between 1 and m_GlobalMaximumNumberOfThreads
  m_GlobalDefaultNumberOfThreads  = vcl_min( m_GlobalDefaultNumberOfThreads,
                                              m_GlobalMaximumNumberOfThreads );
  m_GlobalDefaultNumberOfThreads  = vcl_max( m_GlobalDefaultNumberOfThreads,
                                              NumericTraits<ThreadIdType>::OneValue() );

}

void MultiThreader::SetNumberOfThreads(ThreadIdType numberOfThreads)
{
  if( m_NumberOfThreads == numberOfThreads &&
      numberOfThreads <= m_GlobalMaximumNumberOfThreads )
    {
    return;
    }

  m_NumberOfThreads = numberOfThreads;

  // clamp between 1 and m_GlobalMaximumNumberOfThreads
  m_NumberOfThreads  = vcl_min( m_NumberOfThreads,
                                 m_GlobalMaximumNumberOfThreads );
  m_NumberOfThreads  = vcl_max( m_NumberOfThreads, NumericTraits<ThreadIdType>::OneValue() );

}

ThreadIdType MultiThreader::GetGlobalDefaultNumberOfThreads()
{
  // if default number has been set then don't try to update it; just
  // return the value
  if( m_GlobalDefaultNumberOfThreads != 0 )
    {
    return m_GlobalDefaultNumberOfThreads;
    }

  /* The ITK_NUMBER_OF_THREADS_ENV_LIST contains is an
   * environmental variable that holds a ':' separated
   * list of environmental variables that whould be
   * queried in order for setting the m_GlobalMaximumNumberOfThreads.
   *
   * This is intended to be a mechanism suitable to easy
   * runtime modification to ease using the proper number
   * of threads for load balancing batch processing
   * systems where the number of threads
   * authorized for use may be less than the number
   * of physical processors on the computer.
   *
   * This list contains the Sun|Oracle Grid Engine
   * environmental variable "NSLOTS" by default
   */
  std::vector<std::string> ITK_NUMBER_OF_THREADS_ENV_LIST;
  itksys_stl::string       itkNumberOfThreadsEvnListString = "";
  if( itksys::SystemTools::GetEnv("ITK_NUMBER_OF_THREADS_ENV_LIST",
                                  itkNumberOfThreadsEvnListString) )
    {
    // NOTE: We always put "ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS" at the end
    // unconditionally.
    itkNumberOfThreadsEvnListString += ":ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS";
    }
  else
    {
    itkNumberOfThreadsEvnListString = "NSLOTS:ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS";
    }
    {
    std::stringstream numberOfThreadsEnvListStream(itkNumberOfThreadsEvnListString);
    std::string       item;
    while( std::getline(numberOfThreadsEnvListStream, item, ':') )
      {
      if( item.size() > 0 ) // Do not add empty items.
        {
        ITK_NUMBER_OF_THREADS_ENV_LIST.push_back(item);
        }
      }
    }
  // first, check for environment variable
  itksys_stl::string itkGlobalDefaultNumberOfThreadsEnv = "0";
  for( std::vector<std::string>::const_iterator lit = ITK_NUMBER_OF_THREADS_ENV_LIST.begin();
       lit != ITK_NUMBER_OF_THREADS_ENV_LIST.end();
       ++lit )
    {
    if( itksys::SystemTools::GetEnv(lit->c_str(), itkGlobalDefaultNumberOfThreadsEnv) )
      {
      m_GlobalDefaultNumberOfThreads =
        static_cast<ThreadIdType>( atoi( itkGlobalDefaultNumberOfThreadsEnv.c_str() ) );
      }
    }

  // otherwise, set number of threads based on system information
  if( m_GlobalDefaultNumberOfThreads <= 0 )
    {
    const ThreadIdType num = GetGlobalDefaultNumberOfThreadsByPlatform();
    m_GlobalDefaultNumberOfThreads = num;
    }

  // limit the number of threads to m_GlobalMaximumNumberOfThreads
  m_GlobalDefaultNumberOfThreads  = vcl_min( m_GlobalDefaultNumberOfThreads,
                                              m_GlobalMaximumNumberOfThreads );

  // verify that the default number of threads is larger than zero
  m_GlobalDefaultNumberOfThreads  = vcl_max( m_GlobalDefaultNumberOfThreads,
                                              NumericTraits<ThreadIdType>::OneValue() );

  return m_GlobalDefaultNumberOfThreads;
}

// Constructor. Default all the methods to NULL. Since the
// ThreadInfoArray is static, the ThreadIDs can be initialized here
// and will not change.

MultiThreader::MultiThreader() : m_ThreadPool(ThreadPool::GetInstance() ), m_UseThreadPool(false)
{
  for( ThreadIdType i = 0; i < ITK_MAX_THREADS; ++i )
    {
    m_ThreadInfoArray[i].ThreadID           = i;
    m_ThreadInfoArray[i].ActiveFlag         = ITK_NULLPTR;
    m_ThreadInfoArray[i].ActiveFlagLock     = ITK_NULLPTR;

    m_MultipleMethod[i]                     = ITK_NULLPTR;
    m_MultipleData[i]                       = ITK_NULLPTR;

    m_SpawnedThreadActiveFlag[i]            = 0;
    m_SpawnedThreadActiveFlagLock[i]        = ITK_NULLPTR;
    m_SpawnedThreadInfoArray[i].ThreadID    = i;
    }

  m_SingleMethod = ITK_NULLPTR;
  m_SingleData = ITK_NULLPTR;
  m_NumberOfThreads = this->GetGlobalDefaultNumberOfThreads();

  this->SetUseThreadPool( MultiThreader::GetGlobalDefaultUseThreadPool() );
}

MultiThreader::~MultiThreader()
{
}

// Set the user defined method that will be run on NumberOfThreads threads
// when SingleMethodExecute is called.
void MultiThreader::SetSingleMethod(ThreadFunctionType f, void *data)
{
  m_SingleMethod = f;
  m_SingleData   = data;
}

// Set one of the user defined methods that will be run on NumberOfThreads
// threads when MultipleMethodExecute is called. This method should be
// called with index = 0, 1, ..,  NumberOfThreads-1 to set up all the
// required user defined methods
void MultiThreader::SetMultipleMethod(ThreadIdType index, ThreadFunctionType f, void *data)
{
  // You can only set the method for 0 through NumberOfThreads-1
  if( index >= m_NumberOfThreads )
    {
    itkExceptionMacro(<< "Can't set method " << index << " with a thread count of " << m_NumberOfThreads);
    }
  else
    {
    m_MultipleMethod[index] = f;
    m_MultipleData[index]   = data;
    }
}

// Execute the method set as the SingleMethod on NumberOfThreads threads.
void MultiThreader::SingleMethodExecute()
{
  ThreadIdType        thread_loop = 0;
  ThreadProcessIdType process_id[ITK_MAX_THREADS];

  if( !m_SingleMethod )
    {
    itkExceptionMacro(<< "No single method set!");
    }

  // obey the global maximum number of threads limit
  m_NumberOfThreads = vcl_min( m_GlobalMaximumNumberOfThreads, m_NumberOfThreads );

  // Spawn a set of threads through the SingleMethodProxy. Exceptions
  // thrown from a thread will be caught by the SingleMethodProxy. A
  // naive mechanism is in place for determining whether a thread
  // threw an exception.
  //
  // Thanks to Hannu Helminen for suggestions on how to catch
  // exceptions thrown by threads.
  bool        exceptionOccurred = false;
  std::string exceptionDetails;
  try
    {
    for( thread_loop = 1; thread_loop < m_NumberOfThreads; ++thread_loop )
      {
      m_ThreadInfoArray[thread_loop].UserData    = m_SingleData;
      m_ThreadInfoArray[thread_loop].NumberOfThreads = m_NumberOfThreads;
      m_ThreadInfoArray[thread_loop].ThreadFunction = m_SingleMethod;

      process_id[thread_loop] =
        this->DispatchSingleMethodThread(&m_ThreadInfoArray[thread_loop]);
      }
    }
  catch( std::exception & e )
    {
    // get the details of the exception to rethrow them
    exceptionDetails = e.what();
    // If creation of any thread failed, we must make sure that all
    // threads are correctly cleaned
    exceptionOccurred = true;
    }
  catch( ... )
    {
    // If creation of any thread failed, we must make sure that all
    // threads are correctly cleaned
    exceptionOccurred = true;
    }

  // Now, the parent thread calls this->SingleMethod() itself
  //
  //
  try
    {
    m_ThreadInfoArray[0].UserData = m_SingleData;
    m_ThreadInfoArray[0].NumberOfThreads = m_NumberOfThreads;
    m_SingleMethod( (void *)( &m_ThreadInfoArray[0] ) );
    }
  catch( ProcessAborted & )
    {
    // Need cleanup and rethrow ProcessAborted
    // close down other threads
    for( thread_loop = 1; thread_loop < m_NumberOfThreads; ++thread_loop )
      {
      try
        {
        this->WaitForSingleMethodThread(process_id[thread_loop]);
        }
      catch( ... )
        {
        }
      }
    // rethrow
    throw;
    }
  catch( std::exception & e )
    {
    // get the details of the exception to rethrow them
    exceptionDetails = e.what();
    // if this method fails, we must make sure all threads are
    // correctly cleaned
    exceptionOccurred = true;
    }
  catch( ... )
    {
    // if this method fails, we must make sure all threads are
    // correctly cleaned
    exceptionOccurred = true;
    }
  // The parent thread has finished this->SingleMethod() - so now it
  // waits for each of the other processes to exit
  for( thread_loop = 1; thread_loop < m_NumberOfThreads; ++thread_loop )
    {
    try
      {
      this->WaitForSingleMethodThread(process_id[thread_loop]);
      if( m_ThreadInfoArray[thread_loop].ThreadExitCode
          != ThreadInfoStruct::SUCCESS )
        {
        exceptionOccurred = true;
        }
      }
    catch( std::exception & e )
      {
      // get the details of the exception to rethrow them
      exceptionDetails = e.what();
      exceptionOccurred = true;
      }
    catch( ... )
      {
      exceptionOccurred = true;
      }
    }

  if( exceptionOccurred )
    {
    if( exceptionDetails.empty() )
      {
      itkExceptionMacro("Exception occurred during SingleMethodExecute");
      }
    else
      {
      itkExceptionMacro(<< "Exception occurred during SingleMethodExecute" << std::endl << exceptionDetails);
      }
    }
}

ITK_THREAD_RETURN_TYPE
MultiThreader
::SingleMethodProxy(void *arg)
{
  // grab the ThreadInfoStruct originally prescribed
  MultiThreader::ThreadInfoStruct
  * threadInfoStruct =
    reinterpret_cast<MultiThreader::ThreadInfoStruct *>( arg );

  // execute the user specified threader callback, catching any exceptions
  try
    {
    ( *threadInfoStruct->ThreadFunction )(threadInfoStruct);
    threadInfoStruct->ThreadExitCode = MultiThreader::ThreadInfoStruct::SUCCESS;
    }
  catch( ProcessAborted & )
    {
    threadInfoStruct->ThreadExitCode =
      MultiThreader::ThreadInfoStruct::ITK_PROCESS_ABORTED_EXCEPTION;
    }
  catch( ExceptionObject & )
    {
    threadInfoStruct->ThreadExitCode =
      MultiThreader::ThreadInfoStruct::ITK_EXCEPTION;
    }
  catch( std::exception & )
    {
    threadInfoStruct->ThreadExitCode =
      MultiThreader::ThreadInfoStruct::STD_EXCEPTION;
    }
  catch( ... )
    {
    threadInfoStruct->ThreadExitCode = MultiThreader::ThreadInfoStruct::UNKNOWN;
    }

  return ITK_THREAD_RETURN_VALUE;
}

ThreadProcessIdType
MultiThreader
::DispatchSingleMethodThread(ThreadInfoStruct *info)
{
  if(this->m_UseThreadPool)
    {
    return this->ThreadPoolDispatchSingleMethodThread(info);
    }
  return this->SpawnDispatchSingleMethodThread(info);
}

void
MultiThreader
::WaitForSingleMethodThread(ThreadProcessIdType threadHandle)
{
  if(this->m_UseThreadPool)
    {
    this->ThreadPoolWaitForSingleMethodThread(threadHandle);
    }
  else
    {
    this->SpawnWaitForSingleMethodThread(threadHandle);
    }
}

// Print method for the multithreader
void MultiThreader::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "Thread Count: " << m_NumberOfThreads << "\n";
  os << indent << "Global Maximum Number Of Threads: "
     << m_GlobalMaximumNumberOfThreads << std::endl;
  os << indent << "Global Default Number Of Threads: "
     << m_GlobalDefaultNumberOfThreads << std::endl;
}

}
<commit_msg>BUG: Fix obscure race condition on access thread pool initialization<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
/*=========================================================================
 *
 *  Portions of this file are subject to the VTK Toolkit Version 3 copyright.
 *
 *  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
 *
 *  For complete copyright, license and disclaimer of warranty information
 *  please refer to the NOTICE file at the top of the ITK source tree.
 *
 *=========================================================================*/
#include "itkMultiThreader.h"
#include "itkNumericTraits.h"
#include <iostream>
#include "vcl_algorithm.h"

#if defined(ITK_USE_PTHREADS)
#include "itkMultiThreaderPThreads.cxx"
#elif defined(ITK_USE_WIN32_THREADS)
#include "itkMultiThreaderWinThreads.cxx"
#else
#include "itkMultiThreaderNoThreads.cxx"
#endif

namespace itk
{

// GlobalDefaultUseThreadPoolIsInitialized is used only in this
// file to ensure that the ITK_USE_THREADPOOL environmenal variable
// is only used as a fall back option.  If the SetGlobalDefaultUseThreadPool
// API is ever used by the developer, the developers choice is
// respected over the environmental variable.
static bool GlobalDefaultUseThreadPoolIsInitialized=false;
static SimpleFastMutexLock globalDefaultInitializerLock;

bool MultiThreader::m_GlobalDefaultUseThreadPool = false;

void MultiThreader::SetGlobalDefaultUseThreadPool( const bool GlobalDefaultUseThreadPool )
  {
  m_GlobalDefaultUseThreadPool = GlobalDefaultUseThreadPool;
  GlobalDefaultUseThreadPoolIsInitialized=true;
  }

bool MultiThreader::GetGlobalDefaultUseThreadPool( )
  {
  // This method must be concurrent thread safe

  if( !GlobalDefaultUseThreadPoolIsInitialized )
    {

    MutexLockHolder< SimpleFastMutexLock > lock(globalDefaultInitializerLock);

    // After we have the lock, double check the initialization
    // flag to ensure it hasn't been changed by another thread.

    if (!GlobalDefaultUseThreadPoolIsInitialized )
      {
      // look for runtime request to use thread pool
      std::string use_threadpool;

      if( itksys::SystemTools::GetEnv("ITK_USE_THREADPOOL",use_threadpool) )
        {

        use_threadpool = itksys::SystemTools::UpperCase(use_threadpool);

        // NOTE: GlobalDefaultUseThreadPoolIsInitialized=true after this call
        if(use_threadpool != "NO" && use_threadpool != "OFF" && use_threadpool != "FALSE")
          {
          MultiThreader::SetGlobalDefaultUseThreadPool( true );
          }
        else
          {
          MultiThreader::SetGlobalDefaultUseThreadPool( false );
          }
        }

      // always set that we are initialized
      GlobalDefaultUseThreadPoolIsInitialized=true;
      }
    }
  return m_GlobalDefaultUseThreadPool;
  }

// Initialize static member that controls global maximum number of threads.
ThreadIdType MultiThreader::m_GlobalMaximumNumberOfThreads = ITK_MAX_THREADS;

// Initialize static member that controls global default number of threads : 0
// => Not initialized.
ThreadIdType MultiThreader::m_GlobalDefaultNumberOfThreads = 0;

void MultiThreader::SetGlobalMaximumNumberOfThreads(ThreadIdType val)
{
  m_GlobalMaximumNumberOfThreads = val;

  // clamp between 1 and ITK_MAX_THREADS
  m_GlobalMaximumNumberOfThreads = vcl_min( m_GlobalMaximumNumberOfThreads,
                                             (ThreadIdType) ITK_MAX_THREADS );
  m_GlobalMaximumNumberOfThreads = vcl_max( m_GlobalMaximumNumberOfThreads,
                                             NumericTraits<ThreadIdType>::OneValue() );

  // If necessary reset the default to be used from now on.
  m_GlobalDefaultNumberOfThreads = vcl_min( m_GlobalDefaultNumberOfThreads,
                                             m_GlobalMaximumNumberOfThreads);
}

ThreadIdType MultiThreader::GetGlobalMaximumNumberOfThreads()
{
  return m_GlobalMaximumNumberOfThreads;
}

void MultiThreader::SetGlobalDefaultNumberOfThreads(ThreadIdType val)
{
  m_GlobalDefaultNumberOfThreads = val;

  // clamp between 1 and m_GlobalMaximumNumberOfThreads
  m_GlobalDefaultNumberOfThreads  = vcl_min( m_GlobalDefaultNumberOfThreads,
                                              m_GlobalMaximumNumberOfThreads );
  m_GlobalDefaultNumberOfThreads  = vcl_max( m_GlobalDefaultNumberOfThreads,
                                              NumericTraits<ThreadIdType>::OneValue() );

}

void MultiThreader::SetNumberOfThreads(ThreadIdType numberOfThreads)
{
  if( m_NumberOfThreads == numberOfThreads &&
      numberOfThreads <= m_GlobalMaximumNumberOfThreads )
    {
    return;
    }

  m_NumberOfThreads = numberOfThreads;

  // clamp between 1 and m_GlobalMaximumNumberOfThreads
  m_NumberOfThreads  = vcl_min( m_NumberOfThreads,
                                 m_GlobalMaximumNumberOfThreads );
  m_NumberOfThreads  = vcl_max( m_NumberOfThreads, NumericTraits<ThreadIdType>::OneValue() );

}

ThreadIdType MultiThreader::GetGlobalDefaultNumberOfThreads()
{
  // if default number has been set then don't try to update it; just
  // return the value
  if( m_GlobalDefaultNumberOfThreads != 0 )
    {
    return m_GlobalDefaultNumberOfThreads;
    }

  /* The ITK_NUMBER_OF_THREADS_ENV_LIST contains is an
   * environmental variable that holds a ':' separated
   * list of environmental variables that whould be
   * queried in order for setting the m_GlobalMaximumNumberOfThreads.
   *
   * This is intended to be a mechanism suitable to easy
   * runtime modification to ease using the proper number
   * of threads for load balancing batch processing
   * systems where the number of threads
   * authorized for use may be less than the number
   * of physical processors on the computer.
   *
   * This list contains the Sun|Oracle Grid Engine
   * environmental variable "NSLOTS" by default
   */
  std::vector<std::string> ITK_NUMBER_OF_THREADS_ENV_LIST;
  itksys_stl::string       itkNumberOfThreadsEvnListString = "";
  if( itksys::SystemTools::GetEnv("ITK_NUMBER_OF_THREADS_ENV_LIST",
                                  itkNumberOfThreadsEvnListString) )
    {
    // NOTE: We always put "ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS" at the end
    // unconditionally.
    itkNumberOfThreadsEvnListString += ":ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS";
    }
  else
    {
    itkNumberOfThreadsEvnListString = "NSLOTS:ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS";
    }
    {
    std::stringstream numberOfThreadsEnvListStream(itkNumberOfThreadsEvnListString);
    std::string       item;
    while( std::getline(numberOfThreadsEnvListStream, item, ':') )
      {
      if( item.size() > 0 ) // Do not add empty items.
        {
        ITK_NUMBER_OF_THREADS_ENV_LIST.push_back(item);
        }
      }
    }
  // first, check for environment variable
  itksys_stl::string itkGlobalDefaultNumberOfThreadsEnv = "0";
  for( std::vector<std::string>::const_iterator lit = ITK_NUMBER_OF_THREADS_ENV_LIST.begin();
       lit != ITK_NUMBER_OF_THREADS_ENV_LIST.end();
       ++lit )
    {
    if( itksys::SystemTools::GetEnv(lit->c_str(), itkGlobalDefaultNumberOfThreadsEnv) )
      {
      m_GlobalDefaultNumberOfThreads =
        static_cast<ThreadIdType>( atoi( itkGlobalDefaultNumberOfThreadsEnv.c_str() ) );
      }
    }

  // otherwise, set number of threads based on system information
  if( m_GlobalDefaultNumberOfThreads <= 0 )
    {
    const ThreadIdType num = GetGlobalDefaultNumberOfThreadsByPlatform();
    m_GlobalDefaultNumberOfThreads = num;
    }

  // limit the number of threads to m_GlobalMaximumNumberOfThreads
  m_GlobalDefaultNumberOfThreads  = vcl_min( m_GlobalDefaultNumberOfThreads,
                                              m_GlobalMaximumNumberOfThreads );

  // verify that the default number of threads is larger than zero
  m_GlobalDefaultNumberOfThreads  = vcl_max( m_GlobalDefaultNumberOfThreads,
                                              NumericTraits<ThreadIdType>::OneValue() );

  return m_GlobalDefaultNumberOfThreads;
}

// Constructor. Default all the methods to NULL. Since the
// ThreadInfoArray is static, the ThreadIDs can be initialized here
// and will not change.

MultiThreader::MultiThreader() :
  m_ThreadPool(ThreadPool::GetInstance() ),
  m_UseThreadPool( MultiThreader::GetGlobalDefaultUseThreadPool() )
{
  for( ThreadIdType i = 0; i < ITK_MAX_THREADS; ++i )
    {
    m_ThreadInfoArray[i].ThreadID           = i;
    m_ThreadInfoArray[i].ActiveFlag         = ITK_NULLPTR;
    m_ThreadInfoArray[i].ActiveFlagLock     = ITK_NULLPTR;

    m_MultipleMethod[i]                     = ITK_NULLPTR;
    m_MultipleData[i]                       = ITK_NULLPTR;

    m_SpawnedThreadActiveFlag[i]            = 0;
    m_SpawnedThreadActiveFlagLock[i]        = ITK_NULLPTR;
    m_SpawnedThreadInfoArray[i].ThreadID    = i;
    }

  m_SingleMethod = ITK_NULLPTR;
  m_SingleData = ITK_NULLPTR;
  m_NumberOfThreads = this->GetGlobalDefaultNumberOfThreads();

}

MultiThreader::~MultiThreader()
{
}

// Set the user defined method that will be run on NumberOfThreads threads
// when SingleMethodExecute is called.
void MultiThreader::SetSingleMethod(ThreadFunctionType f, void *data)
{
  m_SingleMethod = f;
  m_SingleData   = data;
}

// Set one of the user defined methods that will be run on NumberOfThreads
// threads when MultipleMethodExecute is called. This method should be
// called with index = 0, 1, ..,  NumberOfThreads-1 to set up all the
// required user defined methods
void MultiThreader::SetMultipleMethod(ThreadIdType index, ThreadFunctionType f, void *data)
{
  // You can only set the method for 0 through NumberOfThreads-1
  if( index >= m_NumberOfThreads )
    {
    itkExceptionMacro(<< "Can't set method " << index << " with a thread count of " << m_NumberOfThreads);
    }
  else
    {
    m_MultipleMethod[index] = f;
    m_MultipleData[index]   = data;
    }
}

// Execute the method set as the SingleMethod on NumberOfThreads threads.
void MultiThreader::SingleMethodExecute()
{
  ThreadIdType        thread_loop = 0;
  ThreadProcessIdType process_id[ITK_MAX_THREADS];

  if( !m_SingleMethod )
    {
    itkExceptionMacro(<< "No single method set!");
    }

  // obey the global maximum number of threads limit
  m_NumberOfThreads = vcl_min( m_GlobalMaximumNumberOfThreads, m_NumberOfThreads );

  // Spawn a set of threads through the SingleMethodProxy. Exceptions
  // thrown from a thread will be caught by the SingleMethodProxy. A
  // naive mechanism is in place for determining whether a thread
  // threw an exception.
  //
  // Thanks to Hannu Helminen for suggestions on how to catch
  // exceptions thrown by threads.
  bool        exceptionOccurred = false;
  std::string exceptionDetails;
  try
    {
    for( thread_loop = 1; thread_loop < m_NumberOfThreads; ++thread_loop )
      {
      m_ThreadInfoArray[thread_loop].UserData    = m_SingleData;
      m_ThreadInfoArray[thread_loop].NumberOfThreads = m_NumberOfThreads;
      m_ThreadInfoArray[thread_loop].ThreadFunction = m_SingleMethod;

      process_id[thread_loop] =
        this->DispatchSingleMethodThread(&m_ThreadInfoArray[thread_loop]);
      }
    }
  catch( std::exception & e )
    {
    // get the details of the exception to rethrow them
    exceptionDetails = e.what();
    // If creation of any thread failed, we must make sure that all
    // threads are correctly cleaned
    exceptionOccurred = true;
    }
  catch( ... )
    {
    // If creation of any thread failed, we must make sure that all
    // threads are correctly cleaned
    exceptionOccurred = true;
    }

  // Now, the parent thread calls this->SingleMethod() itself
  //
  //
  try
    {
    m_ThreadInfoArray[0].UserData = m_SingleData;
    m_ThreadInfoArray[0].NumberOfThreads = m_NumberOfThreads;
    m_SingleMethod( (void *)( &m_ThreadInfoArray[0] ) );
    }
  catch( ProcessAborted & )
    {
    // Need cleanup and rethrow ProcessAborted
    // close down other threads
    for( thread_loop = 1; thread_loop < m_NumberOfThreads; ++thread_loop )
      {
      try
        {
        this->WaitForSingleMethodThread(process_id[thread_loop]);
        }
      catch( ... )
        {
        }
      }
    // rethrow
    throw;
    }
  catch( std::exception & e )
    {
    // get the details of the exception to rethrow them
    exceptionDetails = e.what();
    // if this method fails, we must make sure all threads are
    // correctly cleaned
    exceptionOccurred = true;
    }
  catch( ... )
    {
    // if this method fails, we must make sure all threads are
    // correctly cleaned
    exceptionOccurred = true;
    }
  // The parent thread has finished this->SingleMethod() - so now it
  // waits for each of the other processes to exit
  for( thread_loop = 1; thread_loop < m_NumberOfThreads; ++thread_loop )
    {
    try
      {
      this->WaitForSingleMethodThread(process_id[thread_loop]);
      if( m_ThreadInfoArray[thread_loop].ThreadExitCode
          != ThreadInfoStruct::SUCCESS )
        {
        exceptionOccurred = true;
        }
      }
    catch( std::exception & e )
      {
      // get the details of the exception to rethrow them
      exceptionDetails = e.what();
      exceptionOccurred = true;
      }
    catch( ... )
      {
      exceptionOccurred = true;
      }
    }

  if( exceptionOccurred )
    {
    if( exceptionDetails.empty() )
      {
      itkExceptionMacro("Exception occurred during SingleMethodExecute");
      }
    else
      {
      itkExceptionMacro(<< "Exception occurred during SingleMethodExecute" << std::endl << exceptionDetails);
      }
    }
}

ITK_THREAD_RETURN_TYPE
MultiThreader
::SingleMethodProxy(void *arg)
{
  // grab the ThreadInfoStruct originally prescribed
  MultiThreader::ThreadInfoStruct
  * threadInfoStruct =
    reinterpret_cast<MultiThreader::ThreadInfoStruct *>( arg );

  // execute the user specified threader callback, catching any exceptions
  try
    {
    ( *threadInfoStruct->ThreadFunction )(threadInfoStruct);
    threadInfoStruct->ThreadExitCode = MultiThreader::ThreadInfoStruct::SUCCESS;
    }
  catch( ProcessAborted & )
    {
    threadInfoStruct->ThreadExitCode =
      MultiThreader::ThreadInfoStruct::ITK_PROCESS_ABORTED_EXCEPTION;
    }
  catch( ExceptionObject & )
    {
    threadInfoStruct->ThreadExitCode =
      MultiThreader::ThreadInfoStruct::ITK_EXCEPTION;
    }
  catch( std::exception & )
    {
    threadInfoStruct->ThreadExitCode =
      MultiThreader::ThreadInfoStruct::STD_EXCEPTION;
    }
  catch( ... )
    {
    threadInfoStruct->ThreadExitCode = MultiThreader::ThreadInfoStruct::UNKNOWN;
    }

  return ITK_THREAD_RETURN_VALUE;
}

ThreadProcessIdType
MultiThreader
::DispatchSingleMethodThread(ThreadInfoStruct *info)
{
  if(this->m_UseThreadPool)
    {
    return this->ThreadPoolDispatchSingleMethodThread(info);
    }
  return this->SpawnDispatchSingleMethodThread(info);
}

void
MultiThreader
::WaitForSingleMethodThread(ThreadProcessIdType threadHandle)
{
  if(this->m_UseThreadPool)
    {
    this->ThreadPoolWaitForSingleMethodThread(threadHandle);
    }
  else
    {
    this->SpawnWaitForSingleMethodThread(threadHandle);
    }
}

// Print method for the multithreader
void MultiThreader::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "Thread Count: " << m_NumberOfThreads << "\n";
  os << indent << "Global Maximum Number Of Threads: "
     << m_GlobalMaximumNumberOfThreads << std::endl;
  os << indent << "Global Default Number Of Threads: "
     << m_GlobalDefaultNumberOfThreads << std::endl;
}

}
<|endoftext|>


<commit_before>#include <Internal/CharacterControlManagerImpl.hpp>
#include <Internal/PhysicsModuleImplementation.hpp>
namespace DoremiEngine
{
    namespace Physics
    {
        CharacterControlManagerImpl::CharacterControlManagerImpl(InternalPhysicsUtils& p_utils) : m_utils(p_utils)
        {
            m_manager = PxCreateControllerManager(*m_utils.m_worldScene);
        }
        CharacterControlManagerImpl::~CharacterControlManagerImpl() {}

        int CharacterControlManagerImpl::AddController(int p_id, int p_matID, XMFLOAT3 p_position, XMFLOAT2 p_dimensions)
        {
            // Set start attributes of the controller
            PxCapsuleControllerDesc desc;
            desc.setToDefault();
            desc.position = PxExtendedVec3(p_position.x, p_position.y, p_position.z);
            desc.height = p_dimensions.x;
            desc.radius = p_dimensions.y;
            desc.material = m_utils.m_physicsMaterialManager->GetMaterial(p_matID); // DANGER! Assumes it already has material
            desc.stepOffset = 0.1;
            desc.reportCallback = m_controllerCallback;

            // Hard coded up vector
            desc.upDirection = PxVec3(0, 1, 0);

            bool derp = desc.isValid();

            m_controllers[p_id] = m_manager->createController(desc);
            m_IDsByControllers[m_controllers[p_id]] = p_id;

            SetCallback(p_id, (1 << 0), (1 << 0));

            // Redundant return?
            return p_id;
        }

        int CharacterControlManagerImpl::MoveController(int p_id, XMFLOAT3 p_discplacement, float p_dt)
        {
            /*
            Some variable that apperas to define when the controller stops moving
            Tweak as necessary. Possibly could be moved to some other place.*/
            float m_minDistTraveled = 0;
            // EMPTY FILTERS!
            PxControllerFilters filters;
            m_controllers[p_id]->move(PxVec3(p_discplacement.x, p_discplacement.y, p_discplacement.z), 0, p_dt, filters);
            // Redundant return?
            return p_id;
        }

        XMFLOAT3 CharacterControlManagerImpl::GetPosition(int p_id)
        {
            PxExtendedVec3 p = m_controllers[p_id]->getPosition();
            return XMFLOAT3(p.x, p.y, p.z);
        }

        XMFLOAT4 CharacterControlManagerImpl::GetOrientation(int p_id)
        {
            PxQuat q = m_controllers[p_id]->getActor()->getGlobalPose().q;
            return XMFLOAT4(q.x, q.y, q.z, q.w);
        }

        void CharacterControlManagerImpl::SetCallback(int p_bodyID, int p_filterGroup, int p_filterMask)
        {
            PxFilterData filterData;
            filterData.word0 = p_filterGroup; // Own ID
            filterData.word1 = p_filterMask; // ID mask to filter pairs that trigger contact callback
            PxRigidActor* actor = m_controllers[p_bodyID]->getActor();
            int numShapes = actor->getNbShapes();
            // Magic allocation of memory (i think)
            PxShape** shapes = (PxShape**)m_utils.m_allocator.allocate(sizeof(PxShape*) * numShapes, 0, __FILE__, __LINE__);
            actor->getShapes(shapes, numShapes);
            for(size_t i = 0; i < numShapes; i++)
            {
                PxShape* shape = shapes[i];
                shape->setSimulationFilterData(filterData);
            }
            if(shapes)
            {
                m_utils.m_allocator.deallocate(shapes);
                shapes = NULL;
            }
        }

        void CharacterControlManagerImpl::SetCallbackClass(PxUserControllerHitReport* p_callback) { m_controllerCallback = p_callback; }

        unordered_map<PxController*, int> CharacterControlManagerImpl::GetIdsByControllers() { return m_IDsByControllers; }
    }
}<commit_msg>PhysicsModule: increased security of char control mngr<commit_after>#include <Internal/CharacterControlManagerImpl.hpp>
#include <Internal/PhysicsModuleImplementation.hpp>
namespace DoremiEngine
{
    namespace Physics
    {
        CharacterControlManagerImpl::CharacterControlManagerImpl(InternalPhysicsUtils& p_utils) : m_utils(p_utils)
        {
            m_manager = PxCreateControllerManager(*m_utils.m_worldScene);
        }
        CharacterControlManagerImpl::~CharacterControlManagerImpl() {}

        int CharacterControlManagerImpl::AddController(int p_id, int p_matID, XMFLOAT3 p_position, XMFLOAT2 p_dimensions)
        {
            // Set start attributes of the controller
            PxCapsuleControllerDesc desc;
            desc.setToDefault();
            desc.position = PxExtendedVec3(p_position.x, p_position.y, p_position.z);
            desc.height = p_dimensions.x;
            desc.radius = p_dimensions.y;
            desc.material = m_utils.m_physicsMaterialManager->GetMaterial(p_matID); // DANGER! Assumes it already has material
            if(desc.material == NULL)
            {
                throw std::runtime_error("No physics material exists with that ID");
            }
            desc.stepOffset = 0.1;
            desc.reportCallback = m_controllerCallback;

            // Hard coded up vector
            desc.upDirection = PxVec3(0, 1, 0);

            m_controllers[p_id] = m_manager->createController(desc);
            m_IDsByControllers[m_controllers[p_id]] = p_id;

            SetCallback(p_id, (1 << 0), (1 << 0));

            // Redundant return?
            return p_id;
        }

        int CharacterControlManagerImpl::MoveController(int p_id, XMFLOAT3 p_discplacement, float p_dt)
        {
            /*
            Some variable that apperas to define when the controller stops moving
            Tweak as necessary. Possibly could be moved to some other place.*/
            float m_minDistTraveled = 0;
            // EMPTY FILTERS!
            PxControllerFilters filters;
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + p_id);
            }
            m_controllers[p_id]->move(PxVec3(p_discplacement.x, p_discplacement.y, p_discplacement.z), 0, p_dt, filters);
            // Redundant return?
            return p_id;
        }

        XMFLOAT3 CharacterControlManagerImpl::GetPosition(int p_id)
        {
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + p_id);
            }
            PxExtendedVec3 p = m_controllers[p_id]->getPosition();
            return XMFLOAT3(p.x, p.y, p.z);
        }

        XMFLOAT4 CharacterControlManagerImpl::GetOrientation(int p_id)
        {
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + p_id);
            }
            PxQuat q = m_controllers[p_id]->getActor()->getGlobalPose().q;
            return XMFLOAT4(q.x, q.y, q.z, q.w);
        }

        void CharacterControlManagerImpl::SetCallback(int p_bodyID, int p_filterGroup, int p_filterMask)
        {
            // Check if controller exists
            if(m_controllers.find(p_bodyID) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + p_bodyID);
            }
            PxFilterData filterData;
            filterData.word0 = p_filterGroup; // Own ID
            filterData.word1 = p_filterMask; // ID mask to filter pairs that trigger contact callback
            PxRigidActor* actor = m_controllers[p_bodyID]->getActor();
            int numShapes = actor->getNbShapes();
            // Magic allocation of memory (i think)
            PxShape** shapes = (PxShape**)m_utils.m_allocator.allocate(sizeof(PxShape*) * numShapes, 0, __FILE__, __LINE__);
            actor->getShapes(shapes, numShapes);
            for(size_t i = 0; i < numShapes; i++)
            {
                PxShape* shape = shapes[i];
                shape->setSimulationFilterData(filterData);
            }
            if(shapes)
            {
                m_utils.m_allocator.deallocate(shapes);
                shapes = NULL;
            }
        }

        void CharacterControlManagerImpl::SetCallbackClass(PxUserControllerHitReport* p_callback) { m_controllerCallback = p_callback; }

        unordered_map<PxController*, int> CharacterControlManagerImpl::GetIdsByControllers() { return m_IDsByControllers; }
    }
}<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   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.
*/

/**
  \file    MultiplexOut.cpp
  \author  Jens Krueger
           SCI Institute
           University of Utah
  \date    September 2008
*/

#include "MultiplexOut.h"

#ifdef WIN32
  #include <windows.h>
  // undef stupid windows defines to max and min
  #ifdef max
  #undef max
  #endif

  #ifdef min
  #undef min
  #endif
#endif

#include <stdarg.h>
#include <algorithm>

#include <fstream>
using namespace std;

MultiplexOut::~MultiplexOut() {
  for (size_t i = 0;i<m_vpDebugger.size();i++) {
    m_vpDebugger[i]->Message(_func_, "(MultiplexOut::~MultiplexOut): Shutting down");
    delete m_vpDebugger[i];
  }
}

void MultiplexOut::AddDebugOut(AbstrDebugOut* pDebugger) {
  m_vpDebugger.push_back(pDebugger);
  pDebugger->Message(_func_,"Operating as part of a multiplexed debug out now.");
}

void MultiplexOut::RemoveDebugOut(AbstrDebugOut* pDebugger) {
  std::vector<AbstrDebugOut*>::iterator del;

  del = std::find(m_vpDebugger.begin(), m_vpDebugger.end(), pDebugger);

  if(del != m_vpDebugger.end()) {
    delete *del;
    m_vpDebugger.erase(del);
  }
}

void MultiplexOut::printf(const char* format, ...) const
{
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif

  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->printf(buff);
}

void MultiplexOut::Message(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Message(source,buff);
}

void MultiplexOut::Warning(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Warning(source,buff);
}

void MultiplexOut::Error(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Error(source,buff);
}

void MultiplexOut::SetShowMessages(bool bShowMessages) {
  AbstrDebugOut::SetShowMessages(bShowMessages);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowMessages(bShowMessages);
}

void MultiplexOut::SetShowWarnings(bool bShowWarnings) {
  AbstrDebugOut::SetShowWarnings(bShowWarnings);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowWarnings(bShowWarnings);
}

void MultiplexOut::SetShowErrors(bool bShowErrors) {
  AbstrDebugOut::SetShowErrors(bShowErrors);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowErrors(bShowErrors);
}

void MultiplexOut::SetShowOther(bool bShowOther) {
  AbstrDebugOut::SetShowOther(bShowOther);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowOther(bShowOther);
}

template <class T>
struct deleter : std::unary_function<T, void> {
  void operator()(T* p) const {
    delete p;
  }
};

void MultiplexOut::clear()
{
  std::for_each(m_vpDebugger.begin(), m_vpDebugger.end(),
                deleter<AbstrDebugOut>());
  m_vpDebugger.clear();
}
<commit_msg>Add missing include.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   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.
*/

/**
  \file    MultiplexOut.cpp
  \author  Jens Krueger
           SCI Institute
           University of Utah
  \date    September 2008
*/

#include <functional>
#include "MultiplexOut.h"

#ifdef WIN32
  #include <windows.h>
  // undef stupid windows defines to max and min
  #ifdef max
  #undef max
  #endif

  #ifdef min
  #undef min
  #endif
#endif

#include <stdarg.h>
#include <algorithm>

#include <fstream>
using namespace std;

MultiplexOut::~MultiplexOut() {
  for (size_t i = 0;i<m_vpDebugger.size();i++) {
    m_vpDebugger[i]->Message(_func_, "(MultiplexOut::~MultiplexOut): Shutting down");
    delete m_vpDebugger[i];
  }
}

void MultiplexOut::AddDebugOut(AbstrDebugOut* pDebugger) {
  m_vpDebugger.push_back(pDebugger);
  pDebugger->Message(_func_,"Operating as part of a multiplexed debug out now.");
}

void MultiplexOut::RemoveDebugOut(AbstrDebugOut* pDebugger) {
  std::vector<AbstrDebugOut*>::iterator del;

  del = std::find(m_vpDebugger.begin(), m_vpDebugger.end(), pDebugger);

  if(del != m_vpDebugger.end()) {
    delete *del;
    m_vpDebugger.erase(del);
  }
}

void MultiplexOut::printf(const char* format, ...) const
{
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif

  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->printf(buff);
}

void MultiplexOut::Message(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Message(source,buff);
}

void MultiplexOut::Warning(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Warning(source,buff);
}

void MultiplexOut::Error(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Error(source,buff);
}

void MultiplexOut::SetShowMessages(bool bShowMessages) {
  AbstrDebugOut::SetShowMessages(bShowMessages);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowMessages(bShowMessages);
}

void MultiplexOut::SetShowWarnings(bool bShowWarnings) {
  AbstrDebugOut::SetShowWarnings(bShowWarnings);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowWarnings(bShowWarnings);
}

void MultiplexOut::SetShowErrors(bool bShowErrors) {
  AbstrDebugOut::SetShowErrors(bShowErrors);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowErrors(bShowErrors);
}

void MultiplexOut::SetShowOther(bool bShowOther) {
  AbstrDebugOut::SetShowOther(bShowOther);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowOther(bShowOther);
}

template <class T>
struct deleter : std::unary_function<T, void> {
  void operator()(T* p) const {
    delete p;
  }
};

void MultiplexOut::clear()
{
  std::for_each(m_vpDebugger.begin(), m_vpDebugger.end(),
                deleter<AbstrDebugOut>());
  m_vpDebugger.clear();
}
<|endoftext|>


<commit_before>#pragma once

#include <functional>
#include <gsl/span>
#include <exception>

#include "core/audio/midi.hpp"

#include "util/audio.hpp"

namespace top1 {
  /**
   * Audio Processors are anything that can process audio/midi.
   * They run on the audio thread, and are called by the audio system (Jack).
   * Formally, an audio processor is defined as having a method matching
   * this signature:
   *
   * ```
   * void process(const ProcessData&);
   * ```
   *
   * This method _must_ not be called from anywhere other than the main
   * audio system and it's deligates.
   *
   * If another thread needs access to any of this data, e.g. the audio/midi data,
   * They need an audio processor to read it and store it. It is up to the module
   * in question to handle thread safety.
   */
  namespace audio {

    /**
     * Checks if a type qualifies as an <AudioProcessor>
     */
    template<typename...>
    struct is_audio_processor {}; // TODO: Implementation

    template<typename T>
    struct audio_frame_channels {};

    template<int N>
    struct audio_frame_channels<std::array<float, N>> {
      static constexpr auto value = N;
    };

    namespace detail {
      // No including "core/globals.hpp" in headers
      void registerAudioBufferResize(std::function<void(int)>);
    }

    /**
     * A DynArray that resizes to fit the RealTime bufferSize.
     *
     * This is the container used in AudioProcessors, and it should be used
     * in any place where the realtime data is copied out. It is resized on
     * the bufferSizeChanged event
     */
    template<typename T, std::size_t factor = 1>
    class RTBuffer : public util::dyn_array<T> {
    public:

      RTBuffer(std::size_t initial_size = 0)
        : util::dyn_array<T>(initial_size * factor)
      {
        detail::registerAudioBufferResize([this] (std::size_t newSize) {
            resize(newSize);
          });
      }

      void resize(std::size_t new_size)
      {
        util::dyn_array<T>::resize(new_size * factor);
      }
    };

    template<int N>
    using ProcessBuffer = RTBuffer<std::array<float, N>, 1>;

    /// Non-owning package of data passed to audio processors
    template<int N>
    struct ProcessData {
      static constexpr int channels = N;

      gsl::span<std::array<float, channels>> audio;
      gsl::span<midi::AnyMidiEvent> midi;

      long nframes;

      template<int outN = 0>
      ProcessData<outN> midi_only() {
        return {{nullptr, nullptr}, midi, nframes};
      }

      ProcessData audio_only() {
        return {audio, {nullptr, nullptr}, nframes};
      }

      template<typename T>
      auto redirect(T& buf) ->
      ProcessData<audio_frame_channels<std::remove_reference_t<
                                         decltype(buf[0])>>::value>
      {
        return ProcessData<audio_frame_channels<std::remove_reference_t<
          decltype(buf[0])>>::value>{{buf.data(), nframes}, midi, nframes};
      }

      /// Get only a slice of the audio.
      ///
      /// \param first The index to start from
      /// \param length The number of frames to keep in the slice
      ///   If `length` is negative, `nframes - idx` will be used
      /// \requires parameter `idx` shall be in the range `[0, nframes)`, and
      /// `length` shall be in range `[0, nframes - idx]`
      ProcessData slice(int idx, int length = -1) {
        auto res = *this;
        length = length < 0 ? nframes - idx : length;
        res.nframes = length;
        res.audio = {audio.data() + idx, length};
        return res;
      }

      decltype(auto) begin() { return audio.begin(); }
      decltype(auto) end() { return audio.end(); }
      decltype(auto) begin() const { return audio.begin(); }
      decltype(auto) end() const { return audio.end(); }
    };

  } // audio
} // top1
<commit_msg>Fix for gcc<commit_after>#pragma once

#include <functional>
#include <gsl/span>
#include <exception>

#include "core/audio/midi.hpp"

#include "util/audio.hpp"

namespace top1 {
  /**
   * Audio Processors are anything that can process audio/midi.
   * They run on the audio thread, and are called by the audio system (Jack).
   * Formally, an audio processor is defined as having a method matching
   * this signature:
   *
   * ```
   * void process(const ProcessData&);
   * ```
   *
   * This method _must_ not be called from anywhere other than the main
   * audio system and it's deligates.
   *
   * If another thread needs access to any of this data, e.g. the audio/midi data,
   * They need an audio processor to read it and store it. It is up to the module
   * in question to handle thread safety.
   */
  namespace audio {

    /**
     * Checks if a type qualifies as an <AudioProcessor>
     */
    template<typename...>
    struct is_audio_processor {}; // TODO: Implementation

    template<typename T>
    struct audio_frame_channels;

    template<std::size_t N>
    struct audio_frame_channels<std::array<float, N>> {
      static constexpr auto value = N;
    };

    namespace detail {
      // No including "core/globals.hpp" in headers
      void registerAudioBufferResize(std::function<void(int)>);
    }

    /**
     * A DynArray that resizes to fit the RealTime bufferSize.
     *
     * This is the container used in AudioProcessors, and it should be used
     * in any place where the realtime data is copied out. It is resized on
     * the bufferSizeChanged event
     */
    template<typename T, std::size_t factor = 1>
    class RTBuffer : public util::dyn_array<T> {
    public:

      RTBuffer(std::size_t initial_size = 0)
        : util::dyn_array<T>(initial_size * factor)
      {
        detail::registerAudioBufferResize([this] (std::size_t newSize) {
            resize(newSize);
          });
      }

      void resize(std::size_t new_size)
      {
        util::dyn_array<T>::resize(new_size * factor);
      }
    };

    template<int N>
    using ProcessBuffer = RTBuffer<std::array<float, N>, 1>;

    /// Non-owning package of data passed to audio processors
    template<int N>
    struct ProcessData {
      static constexpr int channels = N;

      gsl::span<std::array<float, channels>> audio;
      gsl::span<midi::AnyMidiEvent> midi;

      long nframes;

      template<int outN = 0>
      ProcessData<outN> midi_only() {
        return {{nullptr, nullptr}, midi, nframes};
      }

      ProcessData audio_only() {
        return {audio, {nullptr, nullptr}, nframes};
      }

      template<typename T>
      auto redirect(T& buf)
      {
        return ProcessData<audio_frame_channels<std::decay_t<
          decltype(buf[0])>>::value>{{buf.data(), nframes}, midi, nframes};
      }

      /// Get only a slice of the audio.
      ///
      /// \param first The index to start from
      /// \param length The number of frames to keep in the slice
      ///   If `length` is negative, `nframes - idx` will be used
      /// \requires parameter `idx` shall be in the range `[0, nframes)`, and
      /// `length` shall be in range `[0, nframes - idx]`
      ProcessData slice(int idx, int length = -1) {
        auto res = *this;
        length = length < 0 ? nframes - idx : length;
        res.nframes = length;
        res.audio = {audio.data() + idx, length};
        return res;
      }

      decltype(auto) begin() { return audio.begin(); }
      decltype(auto) end() { return audio.end(); }
      decltype(auto) begin() const { return audio.begin(); }
      decltype(auto) end() const { return audio.end(); }
    };

  } // audio
} // top1
<|endoftext|>


<commit_before>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QI_ACTOR_HPP_
#define _QI_ACTOR_HPP_

#include <qi/strand.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>

namespace qi
{

/** Class that represents an actor.
 *
 * Inherit from this class if you want your class to be an actor (as in the
 * actor model). This means that your class will receive "messages" and not be
 * called. In other words, there will never be to calls to your object in
 * parallel, they will be queued.
 *
 * \includename{qi/actor.hpp}
 */
class QI_API Actor
{
public:
  Actor()
    : _strand()
  {}
  Actor(const Actor&)
  {}
  Actor(qi::ExecutionContext& ec)
    : _strand(ec)
  {}

  qi::Strand* strand() const
  {
    return &_strand;
  }

private:
  mutable qi::Strand _strand;
};

}

#endif  // _QI_ACTOR_HPP_
<commit_msg>Actor: add explicit constructor<commit_after>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QI_ACTOR_HPP_
#define _QI_ACTOR_HPP_

#include <qi/strand.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>

namespace qi
{

/** Class that represents an actor.
 *
 * Inherit from this class if you want your class to be an actor (as in the
 * actor model). This means that your class will receive "messages" and not be
 * called. In other words, there will never be to calls to your object in
 * parallel, they will be queued.
 *
 * \includename{qi/actor.hpp}
 */
class QI_API Actor
{
public:
  Actor()
    : _strand()
  {}
  Actor(const Actor&)
  {}
  explicit Actor(qi::ExecutionContext& ec)
    : _strand(ec)
  {}

  qi::Strand* strand() const
  {
    return &_strand;
  }

private:
  mutable qi::Strand _strand;
};

}

#endif  // _QI_ACTOR_HPP_
<|endoftext|>


<commit_before>//
//  SDL_gui.cpp
//  TestSDLimage
//
//  Created by Panutat Tejasen on 21/12/2561 BE.
//  Copyright © 2561 Jimmy Software Co., Ltd. All rights reserved.
//

#include "SDL_gui.h"

int GUI_physicalWindowWidth = 0;
int GUI_physicalWindowHeight = 0;

int GUI_windowWidth = 0;
int GUI_windowHeight = 0;

int GUI_expectedWidth = 0;
int GUI_expectedHeight = 0;

float GUI_scale = 1;
float GUI_mouseScale = 1;

static bool done = false;
SDL_Renderer *GUI_renderer = NULL;
SDL_Window *GUI_window = NULL;
GUI_View *GUI_topView = NULL;
GUI_View * GUI_mouseCapturedView = NULL;

static std::function<bool(SDL_Event* ev)> user_handle_events = NULL;

const long MILLESECONDS_PER_FRAME = 1000/60;
static Uint32 timer_start = 0;
static float frameCount = 0;

static void GUI_Loop();
static void handle_events(SDL_Event *ev);

int GUI_Init( const char* title, int expectedWidth, int expectedHeight ) {
    // Get Sccreen size
    SDL_DisplayMode dm;
    if (SDL_GetDesktopDisplayMode(0, &dm) != 0)
    {
        SDL_Log("SDL_GetDesktopDisplayMode failed: %s", SDL_GetError());
        exit(1);
    }
    SDL_Log("Display: %d %d\n", dm.w, dm.h);

    //Now create a window with title "SDL" at 0, 0 on the screen with w:800 h:600 and show it
    // ::SDL_WINDOW_FULLSCREEN,    ::SDL_WINDOW_OPENGL,
    // ::SDL_WINDOW_HIDDEN,        ::SDL_WINDOW_BORDERLESS,
    // ::SDL_WINDOW_RESIZABLE,     ::SDL_WINDOW_MAXIMIZED,
    // ::SDL_WINDOW_MINIMIZED,     ::SDL_WINDOW_INPUT_GRABBED,
    // ::SDL_WINDOW_ALLOW_HIGHDPI.
#if defined(__IPHONEOS__) || defined(__ANDROID__) || defined(__EMSCRIPTEN__)
    int style = SDL_WINDOW_OPENGL|SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_BORDERLESS;
    int cx = 0;
    int cy = 0;
#else
    int style = SDL_WINDOW_OPENGL|SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_RESIZABLE;
    int cx = (dm.w - expectedWidth) / 2;
    int cy = (dm.h - expectedHeight) / 2;
#endif
    GUI_window = SDL_CreateWindow(title, cx, cy, expectedWidth, expectedHeight, style);

    if (GUI_window == NULL) {
        printf("SDL_CreateRenderer Error\n");
        exit(1);
    }

#if defined(WIN32)
    HICON hicon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
	SDL_SysWMinfo info = {0};
	SDL_VERSION(&info.version);
	SDL_GetWindowWMInfo(window, &info);
	HWND hwnd = info.info.win.window;
	SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
	SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
#endif

    //Create a renderer that will draw to the window, -1 specifies that we want to load whichever
    //video driver supports the flags we're passing
    //Flags: SDL_RENDERER_ACCELERATED: We want to use hardware accelerated rendering
    //SDL_RENDERER_PRESENTVSYNC: We want the renderer's present function (update screen) to be
    //synchornized with the monitor's refresh rate
    GUI_renderer = SDL_CreateRenderer(GUI_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (GUI_renderer == NULL) {
        SDL_Log("SDL_CreateRenderer Error\n");
        exit(1);
    }

    SDL_GetWindowSize(GUI_window, &GUI_windowWidth, &GUI_windowHeight);
    SDL_Log("given: %d %d\n", GUI_windowWidth, GUI_windowHeight);

    if( expectedWidth )
        GUI_expectedWidth = expectedWidth;
    else
        GUI_expectedWidth = GUI_windowWidth;

    if( expectedHeight )
        GUI_expectedHeight = expectedHeight;
    else
        GUI_expectedHeight = GUI_windowHeight;

    SDL_Log( "!!! Expected: %i %i\n", GUI_expectedWidth, GUI_expectedHeight );
    GUI_updateScaleParameters();

    return 0;
}

extern void GUI_updateScaleParameters() {
    SDL_GL_GetDrawableSize(GUI_window, &GUI_physicalWindowWidth, &GUI_physicalWindowHeight);
    SDL_Log( "Drawable: %i %i\n", GUI_physicalWindowWidth, GUI_physicalWindowHeight );

#ifdef __ANDROID__
    SDL_Log( "Expected: %i %i\n", GUI_expectedWidth, GUI_expectedHeight );
    // Android always get fullscreen with no retina
    int scalex = GUI_physicalWindowWidth / GUI_expectedWidth;
    int scaley = GUI_physicalWindowHeight / GUI_expectedHeight;
    SDL_Log( "Calc scale: %i %i\n", scalex, scaley );
#else
    int scalex = GUI_physicalWindowWidth / GUI_windowWidth;
    int scaley = GUI_physicalWindowHeight / GUI_windowHeight;
#endif

    GUI_scale = (float)((scalex < scaley) ? scaley : scalex);
    if (GUI_scale < 1.0f) {
        GUI_scale = 1.0f;
    }
    SDL_Log( "Scale: %0.2f\n", GUI_scale );
    SDL_Log( "Mouse Scale: %0.2f\n", GUI_mouseScale );
#ifdef __ANDROID__
    GUI_windowWidth = GUI_physicalWindowWidth / GUI_scale;
    GUI_windowHeight = GUI_physicalWindowHeight / GUI_scale;
    GUI_mouseScale = 1.0;
#else
    if( GUI_windowWidth * GUI_scale != GUI_physicalWindowWidth ||
        GUI_windowHeight * GUI_scale != GUI_physicalWindowHeight ) {

        GUI_windowWidth = GUI_physicalWindowWidth / GUI_scale;
        GUI_windowHeight = GUI_physicalWindowHeight / GUI_scale;
    }
    GUI_mouseScale = GUI_scale;
#endif
    SDL_Log("virtual: %d %d\n", GUI_windowWidth, GUI_windowHeight);
}

void GUI_Run(std::function<bool(SDL_Event* ev)> user_handle_ev) {
    user_handle_events = user_handle_ev;

#ifdef __EMSCRIPTEN__
    // void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop);
    emscripten_set_main_loop(GUI_Loop, 0, 1);
#else
    timer_start = SDL_GetTicks();
    // main loop
    Uint32 startFrame = 0;
    Uint32 endFrame = 0;
    int delay;

    //Uint32 timer_start = SDL_GetTicks();
    while (!done) {
        startFrame = SDL_GetTicks();
        GUI_Loop();
        endFrame = SDL_GetTicks();
        /* figure out how much time we have left, and then sleep */

        delay = MILLESECONDS_PER_FRAME - (endFrame - startFrame);
        if (delay < 0) {
            delay = 0;
        } else if (delay > MILLESECONDS_PER_FRAME) {
            delay = MILLESECONDS_PER_FRAME;
        }
        SDL_Delay(delay);
    }
#endif
}

void GUI_Destroy() {
    SDL_DestroyRenderer(GUI_renderer);
    SDL_DestroyWindow(GUI_window);
}

void GUI_Error(const char* fn, int result) {
    GUI_Log("SDL_gui ERROR: \"%s\" error: %x (%d).\n", fn, result, result);
}

static void GUI_Loop() {
#ifdef __EMSCRIPTEN__
    SDL_Rect rect = {0, 0, GUI_physicalWindowWidth, GUI_physicalWindowHeight};
    SDL_RenderSetViewport(GUI_renderer, &rect);
    SDL_RenderSetClipRect(GUI_renderer, &rect);

    SDL_SetRenderDrawColor(GUI_renderer, 0x64, 0x95, 0xed, 0xff);
    SDL_RenderClear(GUI_renderer);
#else
    SDL_RenderSetViewport(GUI_renderer, NULL);
    SDL_RenderSetClipRect(GUI_renderer, NULL);

    SDL_SetRenderDrawColor(GUI_renderer, 0x64, 0x95, 0xed, 0xff);
    SDL_RenderClear(GUI_renderer);
#endif

    frameCount++;

    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        switch( event.type ) {
            case SDL_QUIT:
                done = 1;
                break;

            case SDL_WINDOWEVENT:
                switch (event.window.event)
                {
                    case SDL_WINDOWEVENT_RESIZED:
                    case SDL_WINDOWEVENT_SIZE_CHANGED:
                        SDL_Log( "Event: Window Resized: %i, %i\n", event.window.data1, event.window.data2 );
                        GUI_windowWidth = event.window.data1;
                        GUI_windowHeight = event.window.data2;

                        GUI_updateScaleParameters();
                        if( GUI_topView ) {
                            GUI_topView->updateLayout();
                        }
                        break;
                }
                break;
        }
        handle_events(&event);
    }
    event.type = GUI_EventUpdate;
    handle_events(&event);
    event.type = GUI_EventPaint;
    handle_events(&event);

    /* update screen */
    SDL_RenderPresent(GUI_renderer);

    Uint32 duration = SDL_GetTicks()-timer_start;
    float fps = frameCount / duration * 1000.0f;
    //printf( "FPS: %0.2f\n", fps );
}

static void handle_events(SDL_Event *ev) {
    if (user_handle_events) {
        if (user_handle_events(ev))
            return;
    }
    if (GUI_mouseCapturedView) {
        switch (ev->type) {
            case SDL_FINGERDOWN:
            case SDL_MOUSEBUTTONDOWN:
                if (GUI_mouseCapturedView->eventHandler(ev))
                    return;
                break;
            case SDL_FINGERMOTION:
            case SDL_MOUSEMOTION:
                if (GUI_mouseCapturedView->eventHandler(ev))
                    return;
                break;
            case SDL_FINGERUP:
            case SDL_MOUSEBUTTONUP:
                if (GUI_mouseCapturedView->eventHandler(ev))
                    return;
                break;
        }
    }
    if( GUI_topView ) {
        if( GUI_topView->eventHandler(ev) )
            return;
    }
}

void GUI_SetMouseCapture( GUI_View *v ) {
    GUI_mouseCapturedView = v;
}

GUI_View *GUI_createTopView(const char* t, int x, int y, int w, int h,
                             std::function<bool(SDL_Event* ev)>userEventHandler) {
    if (GUI_topView) {
        GUI_Log("GUI_TopView existed");
        printf("ERROR: GUI_TopView existed.");
        exit(1);
    }

    GUI_topView = GUI_View::create(NULL,  t, x, y, w, h, userEventHandler);

    GUI_topView->focusable = true;

    if (w == -1) {
        w = GUI_windowWidth - x;
    }

    if (h == -1) {
        h = GUI_windowHeight - y;
    }

    //GUI_topView->resize(w, h);
    //GUI_topView->setMargin(0, 0, 0, 0);
    //GUI_topView->setPadding(0, 0, 0, 0);
    //GUI_topView->setBorder(0);
    //GUI_topView->bgcol = cWhite;

    return GUI_topView;
}

<commit_msg>Fixed emscripten bug<commit_after>//
//  SDL_gui.cpp
//  TestSDLimage
//
//  Created by Panutat Tejasen on 21/12/2561 BE.
//  Copyright © 2561 Jimmy Software Co., Ltd. All rights reserved.
//

#include "SDL_gui.h"

int GUI_physicalWindowWidth = 0;
int GUI_physicalWindowHeight = 0;

int GUI_windowWidth = 0;
int GUI_windowHeight = 0;

int GUI_expectedWidth = 0;
int GUI_expectedHeight = 0;

float GUI_scale = 1;
float GUI_mouseScale = 1;

static bool done = false;
SDL_Renderer *GUI_renderer = NULL;
SDL_Window *GUI_window = NULL;
GUI_View *GUI_topView = NULL;
GUI_View * GUI_mouseCapturedView = NULL;

static std::function<bool(SDL_Event* ev)> user_handle_events = NULL;

const long MILLESECONDS_PER_FRAME = 1000/60;
static Uint32 timer_start = 0;
static float frameCount = 0;

static void GUI_Loop();
static void handle_events(SDL_Event *ev);

int GUI_Init( const char* title, int expectedWidth, int expectedHeight ) {
    // Get Sccreen size
    SDL_DisplayMode dm;
    if (SDL_GetDesktopDisplayMode(0, &dm) != 0)
    {
        SDL_Log("SDL_GetDesktopDisplayMode failed: %s", SDL_GetError());
        exit(1);
    }
    SDL_Log("Display: %d %d\n", dm.w, dm.h);

    //Now create a window with title "SDL" at 0, 0 on the screen with w:800 h:600 and show it
    // ::SDL_WINDOW_FULLSCREEN,    ::SDL_WINDOW_OPENGL,
    // ::SDL_WINDOW_HIDDEN,        ::SDL_WINDOW_BORDERLESS,
    // ::SDL_WINDOW_RESIZABLE,     ::SDL_WINDOW_MAXIMIZED,
    // ::SDL_WINDOW_MINIMIZED,     ::SDL_WINDOW_INPUT_GRABBED,
    // ::SDL_WINDOW_ALLOW_HIGHDPI.
#if defined(__IPHONEOS__) || defined(__ANDROID__) || defined(__EMSCRIPTEN__)
    int style = SDL_WINDOW_OPENGL|SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_BORDERLESS;
    int cx = 0;
    int cy = 0;
#else
    int style = SDL_WINDOW_OPENGL|SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_RESIZABLE;
    int cx = (dm.w - expectedWidth) / 2;
    int cy = (dm.h - expectedHeight) / 2;
#endif
    GUI_window = SDL_CreateWindow(title, cx, cy, expectedWidth, expectedHeight, style);

    if (GUI_window == NULL) {
        printf("SDL_CreateRenderer Error\n");
        exit(1);
    }

#if defined(WIN32)
    HICON hicon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
	SDL_SysWMinfo info = {0};
	SDL_VERSION(&info.version);
	SDL_GetWindowWMInfo(window, &info);
	HWND hwnd = info.info.win.window;
	SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
	SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
#endif

    //Create a renderer that will draw to the window, -1 specifies that we want to load whichever
    //video driver supports the flags we're passing
    //Flags: SDL_RENDERER_ACCELERATED: We want to use hardware accelerated rendering
    //SDL_RENDERER_PRESENTVSYNC: We want the renderer's present function (update screen) to be
    //synchornized with the monitor's refresh rate
    GUI_renderer = SDL_CreateRenderer(GUI_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (GUI_renderer == NULL) {
        SDL_Log("SDL_CreateRenderer Error\n");
        exit(1);
    }

    SDL_GetWindowSize(GUI_window, &GUI_windowWidth, &GUI_windowHeight);
    SDL_Log("given: %d %d\n", GUI_windowWidth, GUI_windowHeight);

    if( expectedWidth )
        GUI_expectedWidth = expectedWidth;
    else
        GUI_expectedWidth = GUI_windowWidth;

    if( expectedHeight )
        GUI_expectedHeight = expectedHeight;
    else
        GUI_expectedHeight = GUI_windowHeight;

    SDL_Log( "!!! Expected: %i %i\n", GUI_expectedWidth, GUI_expectedHeight );
    GUI_updateScaleParameters();

    return 0;
}

extern void GUI_updateScaleParameters() {
    SDL_GL_GetDrawableSize(GUI_window, &GUI_physicalWindowWidth, &GUI_physicalWindowHeight);
    SDL_Log( "Drawable: %i %i\n", GUI_physicalWindowWidth, GUI_physicalWindowHeight );

#ifdef __ANDROID__
    SDL_Log( "Expected: %i %i\n", GUI_expectedWidth, GUI_expectedHeight );
    // Android always get fullscreen with no retina
    int scalex = GUI_physicalWindowWidth / GUI_expectedWidth;
    int scaley = GUI_physicalWindowHeight / GUI_expectedHeight;
    SDL_Log( "Calc scale: %i %i\n", scalex, scaley );
#else
    int scalex = GUI_physicalWindowWidth / GUI_windowWidth;
    int scaley = GUI_physicalWindowHeight / GUI_windowHeight;
#endif

    GUI_scale = (float)((scalex < scaley) ? scaley : scalex);
    if (GUI_scale < 1.0f) {
        GUI_scale = 1.0f;
    }
    SDL_Log( "Scale: %0.2f\n", GUI_scale );
    SDL_Log( "Mouse Scale: %0.2f\n", GUI_mouseScale );
#if defined(__ANDROID__)
    GUI_windowWidth = GUI_physicalWindowWidth / GUI_scale;
    GUI_windowHeight = GUI_physicalWindowHeight / GUI_scale;
    GUI_mouseScale = 1.0;
#else
    if( GUI_windowWidth * GUI_scale != GUI_physicalWindowWidth ||
        GUI_windowHeight * GUI_scale != GUI_physicalWindowHeight ) {

        GUI_windowWidth = GUI_physicalWindowWidth / GUI_scale;
        GUI_windowHeight = GUI_physicalWindowHeight / GUI_scale;
    }
    GUI_mouseScale = GUI_scale;
#endif
    SDL_Log("virtual: %d %d\n", GUI_windowWidth, GUI_windowHeight);
}

void GUI_Run(std::function<bool(SDL_Event* ev)> user_handle_ev) {
    user_handle_events = user_handle_ev;

#ifdef __EMSCRIPTEN__
    // void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop);
    emscripten_set_main_loop(GUI_Loop, 0, 1);
#else
    timer_start = SDL_GetTicks();
    // main loop
    Uint32 startFrame = 0;
    Uint32 endFrame = 0;
    int delay;

    //Uint32 timer_start = SDL_GetTicks();
    while (!done) {
        startFrame = SDL_GetTicks();
        GUI_Loop();
        endFrame = SDL_GetTicks();
        /* figure out how much time we have left, and then sleep */

        delay = MILLESECONDS_PER_FRAME - (endFrame - startFrame);
        if (delay < 0) {
            delay = 0;
        } else if (delay > MILLESECONDS_PER_FRAME) {
            delay = MILLESECONDS_PER_FRAME;
        }
        SDL_Delay(delay);
    }
#endif
}

void GUI_Destroy() {
    SDL_DestroyRenderer(GUI_renderer);
    SDL_DestroyWindow(GUI_window);
}

void GUI_Error(const char* fn, int result) {
    GUI_Log("SDL_gui ERROR: \"%s\" error: %x (%d).\n", fn, result, result);
}

static void GUI_Loop() {
#ifdef __EMSCRIPTEN__
    SDL_Rect rect = {0, 0, GUI_physicalWindowWidth, GUI_physicalWindowHeight};
    SDL_RenderSetViewport(GUI_renderer, &rect);
    SDL_RenderSetClipRect(GUI_renderer, &rect);

    SDL_SetRenderDrawColor(GUI_renderer, 0x64, 0x95, 0xed, 0xff);
    SDL_RenderClear(GUI_renderer);
#else
    SDL_RenderSetViewport(GUI_renderer, NULL);
    SDL_RenderSetClipRect(GUI_renderer, NULL);

    SDL_SetRenderDrawColor(GUI_renderer, 0x64, 0x95, 0xed, 0xff);
    SDL_RenderClear(GUI_renderer);
#endif

    frameCount++;

    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        switch( event.type ) {
            case SDL_QUIT:
                done = 1;
                break;

            case SDL_WINDOWEVENT:
                switch (event.window.event)
                {
                    case SDL_WINDOWEVENT_RESIZED:
                    case SDL_WINDOWEVENT_SIZE_CHANGED:
                        SDL_Log( "Event: Window Resized: %i, %i\n", event.window.data1, event.window.data2 );
                        GUI_windowWidth = event.window.data1;
                        GUI_windowHeight = event.window.data2;

                        GUI_updateScaleParameters();
                        if( GUI_topView ) {
                            GUI_topView->updateLayout();
                        }
                        break;
                }
                break;
        }
        handle_events(&event);
    }
    event.type = GUI_EventUpdate;
    handle_events(&event);
    event.type = GUI_EventPaint;
    handle_events(&event);

    /* update screen */
    SDL_RenderPresent(GUI_renderer);

    Uint32 duration = SDL_GetTicks()-timer_start;
    float fps = frameCount / duration * 1000.0f;
    //printf( "FPS: %0.2f\n", fps );
}

static void handle_events(SDL_Event *ev) {
    if (user_handle_events) {
        if (user_handle_events(ev))
            return;
    }
    if (GUI_mouseCapturedView) {
        switch (ev->type) {
            case SDL_FINGERDOWN:
            case SDL_MOUSEBUTTONDOWN:
                if (GUI_mouseCapturedView->eventHandler(ev))
                    return;
                break;
            case SDL_FINGERMOTION:
            case SDL_MOUSEMOTION:
                if (GUI_mouseCapturedView->eventHandler(ev))
                    return;
                break;
            case SDL_FINGERUP:
            case SDL_MOUSEBUTTONUP:
                if (GUI_mouseCapturedView->eventHandler(ev))
                    return;
                break;
        }
    }
    if( GUI_topView ) {
        if( GUI_topView->eventHandler(ev) )
            return;
    }
}

void GUI_SetMouseCapture( GUI_View *v ) {
    GUI_mouseCapturedView = v;
}

GUI_View *GUI_createTopView(const char* t, int x, int y, int w, int h,
                             std::function<bool(SDL_Event* ev)>userEventHandler) {
    if (GUI_topView) {
        GUI_Log("GUI_TopView existed");
        printf("ERROR: GUI_TopView existed.");
        exit(1);
    }

    GUI_topView = GUI_View::create(NULL,  t, x, y, w, h, userEventHandler);

    GUI_topView->focusable = true;

    if (w == -1) {
        w = GUI_windowWidth - x;
    }

    if (h == -1) {
        h = GUI_windowHeight - y;
    }

    //GUI_topView->resize(w, h);
    //GUI_topView->setMargin(0, 0, 0, 0);
    //GUI_topView->setPadding(0, 0, 0, 0);
    //GUI_topView->setBorder(0);
    //GUI_topView->bgcol = cWhite;

    return GUI_topView;
}

<|endoftext|>