<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/net.hxx>
#include <abaclade/thread.hxx>

#if ABC_HOST_API_POSIX
   #include <arpa/inet.h> // inet_addr()
   #include <errno.h> // EINTR errno
   #include <sys/types.h> // sockaddr sockaddr_in
   #include <sys/socket.h> // accept4() bind() socket()
   #if ABC_HOST_API_FREEBSD
      #include <netinet/in.h>
   #endif
#elif ABC_HOST_API_WIN32
   #include <winsock2.h>
   #include <mswsock.h> // AcceptEx() GetAcceptExSockaddrs()
   #if ABC_HOST_CXX_MSC
      // Silence warnings from system header files.
      #pragma warning(push)

      // “'id' : conversion from 'type1' to 'type2', signed / unsigned mismatch”
      #pragma warning(disable: 4365)
   #endif
   #include <ws2tcpip.h>
   #include <mstcpip.h>
   #if ABC_HOST_CXX_MSC
      #pragma warning(pop)
   #endif
   #if _WIN32_WINNT == 0x0500
      // Additional header required for Windows 2000 IPv6 Tech Preview.
      #include <tpipv6.h>
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace abc { namespace net {

static detail::raw_ip_address const gc_abAny4 = {
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 4
};
static detail::raw_ip_address const gc_abAny6 = {
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 6
};

ip_address const & ip_address::any_ipv4 = static_cast<ip_address const &>(gc_abAny4);
ip_address const & ip_address::any_ipv6 = static_cast<ip_address const &>(gc_abAny6);

}} //namespace abc::net

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace abc { namespace net {

connection::connection(io::filedesc fd, ip_address && ipaddrRemote, port_t portRemote) :
   m_bfrw(io::binary::make_readwriter(_std::move(fd))),
   m_ipaddrRemote(_std::move(ipaddrRemote)),
   m_portRemote(portRemote) {
}

connection::~connection() {
}

}} //namespace abc::net

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace abc { namespace net {

tcp_server::tcp_server(ip_address const & ipaddr, port_t port, unsigned cBacklog /*= 5*/) :
   m_fdSocket(create_socket(ipaddr.version())),
   m_iIPVersion(ipaddr.version()) {
   ABC_TRACE_FUNC(this/*, ipaddr*/, port, cBacklog);

#if ABC_HOST_API_POSIX
   typedef ::sockaddr sockaddr_type;
   typedef ::socklen_t socklen_type;
#elif ABC_HOST_API_WIN32
   typedef ::SOCKADDR sockaddr_type;
   typedef int socklen_type;
#else
   #error "TODO: HOST_API"
#endif
   sockaddr_type * psaServer;
   socklen_type cbServer;
   ::sockaddr_in saServer4;
   ::sockaddr_in6 saServer6;
   switch (m_iIPVersion) {
      case 4:
         psaServer = reinterpret_cast<sockaddr_type *>(&saServer4);
         cbServer = sizeof saServer4;
         memory::clear(&saServer4);
         saServer4.sin_family = AF_INET;
         memory::copy(
            reinterpret_cast<std::uint8_t *>(&saServer4.sin_addr.s_addr),
            ipaddr.raw(),
            sizeof(ip_address::ipv4_type)
         );
         saServer4.sin_addr.s_addr = htonl(saServer4.sin_addr.s_addr);
         saServer4.sin_port = htons(port);
         break;
      case 6:
         psaServer = reinterpret_cast<sockaddr_type *>(&saServer6);
         cbServer = sizeof saServer6;
         memory::clear(&saServer6);
         //saServer6.sin6_flowinfo = 0;
         saServer6.sin6_family = AF_INET6;
         memory::copy(saServer6.sin6_addr.s6_addr, ipaddr.raw(), sizeof(ip_address::ipv6_type));
         saServer6.sin6_port = htons(port);
         break;
      ABC_SWITCH_WITHOUT_DEFAULT
   }
#if ABC_HOST_API_WIN32
   if (::bind(reinterpret_cast< ::SOCKET>(m_fdSocket.get()), psaServer, cbServer) < 0) {
      exception::throw_os_error(static_cast<errint_t>(::WSAGetLastError()));
   }
   if (::listen(reinterpret_cast< ::SOCKET>(m_fdSocket.get()), static_cast<int>(cBacklog)) < 0) {
      exception::throw_os_error(static_cast<errint_t>(::WSAGetLastError()));
   }
#else
   if (::bind(m_fdSocket.get(), psaServer, cbServer) < 0) {
      exception::throw_os_error();
   }
   if (::listen(m_fdSocket.get(), static_cast<int>(cBacklog)) < 0) {
      exception::throw_os_error();
   }
#endif
}

tcp_server::~tcp_server() {
#if ABC_HOST_API_WIN32
   ::WSACleanup();
#endif
}

_std::shared_ptr<connection> tcp_server::accept() {
   ABC_TRACE_FUNC(this);

   io::filedesc fdConnection;
#if ABC_HOST_API_POSIX
   bool bAsync = (this_thread::coroutine_scheduler() != nullptr);
   ::sockaddr * psaClient;
   ::socklen_t cbClient;
   ::sockaddr_in saClient4;
   ::sockaddr_in6 saClient6;
   if (m_iIPVersion == 4) {
      psaClient = reinterpret_cast< ::sockaddr *>(&saClient4);
      cbClient = sizeof saClient4;
   } else {
      psaClient = reinterpret_cast< ::sockaddr *>(&saClient6);
      cbClient = sizeof saClient6;
   }
   for (;;) {
      ::socklen_t cb = cbClient;
   #if ABC_HOST_API_DARWIN
      // accept4() is not available, so emulate it with accept() + fcntl().
      fdConnection = io::filedesc(::accept(m_fdSocket.get(), psaClient, &cb));
      if (fdConnection) {
         /* Note that at this point there’s no hack that will ensure a fork()/exec() from another
         thread won’t leak the file descriptor. That’s the whole point of accept4(). */
         fdConnection.set_close_on_exec(true);
         if (bAsync) {
            fdConnection.set_nonblocking(true);
         }
      }
   #else
      int iFlags = SOCK_CLOEXEC;
      if (bAsync) {
         // Using coroutines, so make the client socket non-blocking.
         iFlags |= SOCK_NONBLOCK;
      }
      fdConnection = io::filedesc(::accept4(m_fdSocket.get(), psaClient, &cb, iFlags));
   #endif
      if (fdConnection) {
         cbClient = cb;
         break;
      }
      int iErr = errno;
      switch (iErr) {
         case EINTR:
            this_coroutine::interruption_point();
            break;
         case EAGAIN:
   #if EWOULDBLOCK != EAGAIN
         case EWOULDBLOCK:
   #endif
            // Wait for m_fdSocket. Accepting a connection is considered a read event.
            this_coroutine::sleep_until_fd_ready(m_fdSocket.get(), false);
            break;
         default:
            exception::throw_os_error(static_cast<errint_t>(iErr));
      }
   }
#elif ABC_HOST_API_WIN32
   union sockaddr_any {
      ::sockaddr_in sa4;
      ::sockaddr_in6 sa6;
   };
   // This weird structure is what ::AcceptEx() expects.
   struct AcceptEx_buffer_t {
      /* This is not present, since we’re not going to wait for data to be received when a new
      connection is established. */
      // std::int8_t abData[0];
      sockaddr_any saaLocal;
      std::int8_t abLocalPadding[16];
      sockaddr_any saaRemote;
      std::int8_t abRemotePadding[16];
   } aebuf;
   static ::DWORD const cbLocalBuf  = sizeof aebuf.saaLocal  + sizeof aebuf.abLocalPadding;
   static ::DWORD const cbRemoteBuf = sizeof aebuf.saaRemote + sizeof aebuf.abRemotePadding;

   fdConnection = create_socket(m_iIPVersion);
   ::DWORD cbRead;
   io::overlapped ovl;
   ovl.Offset = 0;
   ovl.OffsetHigh = 0;
   m_fdSocket.bind_to_this_coroutine_scheduler_iocp();
   if (!::AcceptEx(
      reinterpret_cast< ::SOCKET>(m_fdSocket.get()),
      reinterpret_cast< ::SOCKET>(fdConnection.get()),
      &aebuf, 0 /*don’t wait for data, just wait for a connection*/,
      cbLocalBuf, cbRemoteBuf, &cbRead, &ovl
   )) {
      ::DWORD iErr = static_cast< ::DWORD>(::WSAGetLastError());
      if (iErr == ERROR_IO_PENDING) {
         this_coroutine::sleep_until_fd_ready(m_fdSocket.get(), false, &ovl);
      }
      iErr = ovl.status();
      if (iErr != ERROR_SUCCESS) {
         exception::throw_os_error(iErr);
      }
      cbRead = ovl.transferred_size();
   }

   // Parse the weird buffer.
   ::SOCKADDR * psaClient, * psaLocal;
   int cbClient, cbLocal;
   ::GetAcceptExSockaddrs(
      &aebuf, 0, cbLocalBuf, cbRemoteBuf, &psaLocal, &cbLocal, &psaClient, &cbClient
   );
#else
   #error "TODO: HOST_API"
#endif
   this_coroutine::interruption_point();

   ip_address ipaddrClient;
   port_t portClient;
   // TODO: validate cbClient and set ipaddrClient/portClient using saClient4/6.sin_addr.
   ipaddrClient = ip_address(0);
   portClient = 0;
   return _std::make_shared<connection>(
      _std::move(fdConnection), _std::move(ipaddrClient), portClient
   );
}

/*static*/ io::filedesc tcp_server::create_socket(std::uint8_t iIPVersion) {
   ABC_TRACE_FUNC(iIPVersion);

   if (iIPVersion != 4 && iIPVersion != 6) {
      // TODO: provide more information in the exception.
      ABC_THROW(domain_error, ());
   }
   bool bAsync = (this_thread::coroutine_scheduler() != nullptr);
   int iFamily = (iIPVersion == 4 ? AF_INET : AF_INET6);
   int iType = SOCK_STREAM;
#if ABC_HOST_API_POSIX
   #if !ABC_HOST_API_DARWIN
      iType |= SOCK_CLOEXEC;
      if (bAsync) {
         // Using coroutines, so make this socket non-blocking.
         iType |= SOCK_NONBLOCK;
      }
   #endif
   io::filedesc fd(::socket(iFamily, iType, 0));
   if (!fd) {
      exception::throw_os_error();
   }
   #if ABC_HOST_API_DARWIN
      /* Note that at this point there’s no hack that will ensure a fork()/exec() from another
      thread won’t leak the file descriptor. That’s the whole point of the extra SOCK_* flags. */
      fd.set_close_on_exec(true);
      if (bAsync) {
         fd.set_nonblocking(true);
      }
   #endif
   return _std::move(fd);
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   static std::uint8_t const sc_iWSAMajorVersion = 2, sc_iWSAMinorVersion = 2;
   ::WSADATA wsad;
   if (int iRet = ::WSAStartup(MAKEWORD(sc_iWSAMajorVersion, sc_iWSAMinorVersion), &wsad)) {
      exception::throw_os_error(static_cast<errint_t>(iRet));
   }
   if (
      LOBYTE(wsad.wVersion) != sc_iWSAMajorVersion || HIBYTE(wsad.wVersion) != sc_iWSAMinorVersion
   ) {
      // The loaded WinSock implementation does not support the requested version.
      ::WSACleanup();
      // TODO: use a better exception class.
      ABC_THROW(generic_error, ());
   }

   ::DWORD iFlags = 0;
   if (bAsync) {
      iFlags |= WSA_FLAG_OVERLAPPED;
   }
   #ifdef WSA_FLAG_NO_HANDLE_INHERIT
      iFlags |= WSA_FLAG_NO_HANDLE_INHERIT;
   #endif
   ::SOCKET sock = ::WSASocket(iFamily, iType, 0, nullptr, 0, iFlags);
   if (sock == INVALID_SOCKET) {
      exception::throw_os_error();
   }
   return io::filedesc(reinterpret_cast<io::filedesc_t>(sock));
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else
}

}} //namespace abc::net
<commit_msg>Fix order of operations after abc::this_coroutine::sleep_until_fd_ready()<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/net.hxx>
#include <abaclade/thread.hxx>

#if ABC_HOST_API_POSIX
   #include <arpa/inet.h> // inet_addr()
   #include <errno.h> // EINTR errno
   #include <sys/types.h> // sockaddr sockaddr_in
   #include <sys/socket.h> // accept4() bind() socket()
   #if ABC_HOST_API_FREEBSD
      #include <netinet/in.h>
   #endif
#elif ABC_HOST_API_WIN32
   #include <winsock2.h>
   #include <mswsock.h> // AcceptEx() GetAcceptExSockaddrs()
   #if ABC_HOST_CXX_MSC
      // Silence warnings from system header files.
      #pragma warning(push)

      // “'id' : conversion from 'type1' to 'type2', signed / unsigned mismatch”
      #pragma warning(disable: 4365)
   #endif
   #include <ws2tcpip.h>
   #include <mstcpip.h>
   #if ABC_HOST_CXX_MSC
      #pragma warning(pop)
   #endif
   #if _WIN32_WINNT == 0x0500
      // Additional header required for Windows 2000 IPv6 Tech Preview.
      #include <tpipv6.h>
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace abc { namespace net {

static detail::raw_ip_address const gc_abAny4 = {
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 4
};
static detail::raw_ip_address const gc_abAny6 = {
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 6
};

ip_address const & ip_address::any_ipv4 = static_cast<ip_address const &>(gc_abAny4);
ip_address const & ip_address::any_ipv6 = static_cast<ip_address const &>(gc_abAny6);

}} //namespace abc::net

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace abc { namespace net {

connection::connection(io::filedesc fd, ip_address && ipaddrRemote, port_t portRemote) :
   m_bfrw(io::binary::make_readwriter(_std::move(fd))),
   m_ipaddrRemote(_std::move(ipaddrRemote)),
   m_portRemote(portRemote) {
}

connection::~connection() {
}

}} //namespace abc::net

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace abc { namespace net {

tcp_server::tcp_server(ip_address const & ipaddr, port_t port, unsigned cBacklog /*= 5*/) :
   m_fdSocket(create_socket(ipaddr.version())),
   m_iIPVersion(ipaddr.version()) {
   ABC_TRACE_FUNC(this/*, ipaddr*/, port, cBacklog);

#if ABC_HOST_API_POSIX
   typedef ::sockaddr sockaddr_type;
   typedef ::socklen_t socklen_type;
#elif ABC_HOST_API_WIN32
   typedef ::SOCKADDR sockaddr_type;
   typedef int socklen_type;
#else
   #error "TODO: HOST_API"
#endif
   sockaddr_type * psaServer;
   socklen_type cbServer;
   ::sockaddr_in saServer4;
   ::sockaddr_in6 saServer6;
   switch (m_iIPVersion) {
      case 4:
         psaServer = reinterpret_cast<sockaddr_type *>(&saServer4);
         cbServer = sizeof saServer4;
         memory::clear(&saServer4);
         saServer4.sin_family = AF_INET;
         memory::copy(
            reinterpret_cast<std::uint8_t *>(&saServer4.sin_addr.s_addr),
            ipaddr.raw(),
            sizeof(ip_address::ipv4_type)
         );
         saServer4.sin_addr.s_addr = htonl(saServer4.sin_addr.s_addr);
         saServer4.sin_port = htons(port);
         break;
      case 6:
         psaServer = reinterpret_cast<sockaddr_type *>(&saServer6);
         cbServer = sizeof saServer6;
         memory::clear(&saServer6);
         //saServer6.sin6_flowinfo = 0;
         saServer6.sin6_family = AF_INET6;
         memory::copy(saServer6.sin6_addr.s6_addr, ipaddr.raw(), sizeof(ip_address::ipv6_type));
         saServer6.sin6_port = htons(port);
         break;
      ABC_SWITCH_WITHOUT_DEFAULT
   }
#if ABC_HOST_API_WIN32
   if (::bind(reinterpret_cast< ::SOCKET>(m_fdSocket.get()), psaServer, cbServer) < 0) {
      exception::throw_os_error(static_cast<errint_t>(::WSAGetLastError()));
   }
   if (::listen(reinterpret_cast< ::SOCKET>(m_fdSocket.get()), static_cast<int>(cBacklog)) < 0) {
      exception::throw_os_error(static_cast<errint_t>(::WSAGetLastError()));
   }
#else
   if (::bind(m_fdSocket.get(), psaServer, cbServer) < 0) {
      exception::throw_os_error();
   }
   if (::listen(m_fdSocket.get(), static_cast<int>(cBacklog)) < 0) {
      exception::throw_os_error();
   }
#endif
}

tcp_server::~tcp_server() {
#if ABC_HOST_API_WIN32
   ::WSACleanup();
#endif
}

_std::shared_ptr<connection> tcp_server::accept() {
   ABC_TRACE_FUNC(this);

   io::filedesc fdConnection;
#if ABC_HOST_API_POSIX
   bool bAsync = (this_thread::coroutine_scheduler() != nullptr);
   ::sockaddr * psaClient;
   ::socklen_t cbClient;
   ::sockaddr_in saClient4;
   ::sockaddr_in6 saClient6;
   if (m_iIPVersion == 4) {
      psaClient = reinterpret_cast< ::sockaddr *>(&saClient4);
      cbClient = sizeof saClient4;
   } else {
      psaClient = reinterpret_cast< ::sockaddr *>(&saClient6);
      cbClient = sizeof saClient6;
   }
   for (;;) {
      ::socklen_t cb = cbClient;
   #if ABC_HOST_API_DARWIN
      // accept4() is not available, so emulate it with accept() + fcntl().
      fdConnection = io::filedesc(::accept(m_fdSocket.get(), psaClient, &cb));
      if (fdConnection) {
         /* Note that at this point there’s no hack that will ensure a fork()/exec() from another
         thread won’t leak the file descriptor. That’s the whole point of accept4(). */
         fdConnection.set_close_on_exec(true);
         if (bAsync) {
            fdConnection.set_nonblocking(true);
         }
      }
   #else
      int iFlags = SOCK_CLOEXEC;
      if (bAsync) {
         // Using coroutines, so make the client socket non-blocking.
         iFlags |= SOCK_NONBLOCK;
      }
      fdConnection = io::filedesc(::accept4(m_fdSocket.get(), psaClient, &cb, iFlags));
   #endif
      if (fdConnection) {
         cbClient = cb;
         break;
      }
      int iErr = errno;
      switch (iErr) {
         case EINTR:
            this_coroutine::interruption_point();
            break;
         case EAGAIN:
   #if EWOULDBLOCK != EAGAIN
         case EWOULDBLOCK:
   #endif
            // Wait for m_fdSocket. Accepting a connection is considered a read event.
            this_coroutine::sleep_until_fd_ready(m_fdSocket.get(), false);
            break;
         default:
            exception::throw_os_error(static_cast<errint_t>(iErr));
      }
   }
#elif ABC_HOST_API_WIN32
   union sockaddr_any {
      ::sockaddr_in sa4;
      ::sockaddr_in6 sa6;
   };
   // This weird structure is what ::AcceptEx() expects.
   struct AcceptEx_buffer_t {
      /* This is not present, since we’re not going to wait for data to be received when a new
      connection is established. */
      // std::int8_t abData[0];
      sockaddr_any saaLocal;
      std::int8_t abLocalPadding[16];
      sockaddr_any saaRemote;
      std::int8_t abRemotePadding[16];
   } aebuf;
   static ::DWORD const cbLocalBuf  = sizeof aebuf.saaLocal  + sizeof aebuf.abLocalPadding;
   static ::DWORD const cbRemoteBuf = sizeof aebuf.saaRemote + sizeof aebuf.abRemotePadding;

   fdConnection = create_socket(m_iIPVersion);
   ::DWORD cbRead;
   io::overlapped ovl;
   ovl.Offset = 0;
   ovl.OffsetHigh = 0;
   m_fdSocket.bind_to_this_coroutine_scheduler_iocp();
   if (!::AcceptEx(
      reinterpret_cast< ::SOCKET>(m_fdSocket.get()),
      reinterpret_cast< ::SOCKET>(fdConnection.get()),
      &aebuf, 0 /*don’t wait for data, just wait for a connection*/,
      cbLocalBuf, cbRemoteBuf, &cbRead, &ovl
   )) {
      ::DWORD iErr = static_cast< ::DWORD>(::WSAGetLastError());
      if (iErr == ERROR_IO_PENDING) {
         this_coroutine::sleep_until_fd_ready(m_fdSocket.get(), false, &ovl);
         iErr = ovl.status();
         cbRead = ovl.transferred_size();
      }
      if (iErr != ERROR_SUCCESS) {
         exception::throw_os_error(iErr);
      }
   }

   // Parse the weird buffer.
   ::SOCKADDR * psaClient, * psaLocal;
   int cbClient, cbLocal;
   ::GetAcceptExSockaddrs(
      &aebuf, 0, cbLocalBuf, cbRemoteBuf, &psaLocal, &cbLocal, &psaClient, &cbClient
   );
#else
   #error "TODO: HOST_API"
#endif
   this_coroutine::interruption_point();

   ip_address ipaddrClient;
   port_t portClient;
   // TODO: validate cbClient and set ipaddrClient/portClient using saClient4/6.sin_addr.
   ipaddrClient = ip_address(0);
   portClient = 0;
   return _std::make_shared<connection>(
      _std::move(fdConnection), _std::move(ipaddrClient), portClient
   );
}

/*static*/ io::filedesc tcp_server::create_socket(std::uint8_t iIPVersion) {
   ABC_TRACE_FUNC(iIPVersion);

   if (iIPVersion != 4 && iIPVersion != 6) {
      // TODO: provide more information in the exception.
      ABC_THROW(domain_error, ());
   }
   bool bAsync = (this_thread::coroutine_scheduler() != nullptr);
   int iFamily = (iIPVersion == 4 ? AF_INET : AF_INET6);
   int iType = SOCK_STREAM;
#if ABC_HOST_API_POSIX
   #if !ABC_HOST_API_DARWIN
      iType |= SOCK_CLOEXEC;
      if (bAsync) {
         // Using coroutines, so make this socket non-blocking.
         iType |= SOCK_NONBLOCK;
      }
   #endif
   io::filedesc fd(::socket(iFamily, iType, 0));
   if (!fd) {
      exception::throw_os_error();
   }
   #if ABC_HOST_API_DARWIN
      /* Note that at this point there’s no hack that will ensure a fork()/exec() from another
      thread won’t leak the file descriptor. That’s the whole point of the extra SOCK_* flags. */
      fd.set_close_on_exec(true);
      if (bAsync) {
         fd.set_nonblocking(true);
      }
   #endif
   return _std::move(fd);
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   static std::uint8_t const sc_iWSAMajorVersion = 2, sc_iWSAMinorVersion = 2;
   ::WSADATA wsad;
   if (int iRet = ::WSAStartup(MAKEWORD(sc_iWSAMajorVersion, sc_iWSAMinorVersion), &wsad)) {
      exception::throw_os_error(static_cast<errint_t>(iRet));
   }
   if (
      LOBYTE(wsad.wVersion) != sc_iWSAMajorVersion || HIBYTE(wsad.wVersion) != sc_iWSAMinorVersion
   ) {
      // The loaded WinSock implementation does not support the requested version.
      ::WSACleanup();
      // TODO: use a better exception class.
      ABC_THROW(generic_error, ());
   }

   ::DWORD iFlags = 0;
   if (bAsync) {
      iFlags |= WSA_FLAG_OVERLAPPED;
   }
   #ifdef WSA_FLAG_NO_HANDLE_INHERIT
      iFlags |= WSA_FLAG_NO_HANDLE_INHERIT;
   #endif
   ::SOCKET sock = ::WSASocket(iFamily, iType, 0, nullptr, 0, iFlags);
   if (sock == INVALID_SOCKET) {
      exception::throw_os_error();
   }
   return io::filedesc(reinterpret_cast<io::filedesc_t>(sock));
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else
}

}} //namespace abc::net
<|endoftext|>


<commit_before>#include "Bridge.h"

#include <cmath>
#include "Player.h"
#include "../gamestate/ActorAPI.h"
#include "../gamestate/EventMap.h"

DynamicBridgePiece::DynamicBridgePiece(std::shared_ptr<ActorAPI> api, double x, double y, DynamicBridgeType type, uint idx)
    : SolidObject(api, x, y, false) {
    canBeFrozen = false;
    loadResources("Object/BridgePiece");

    QString typeName = "ROPE";
    switch (type) {
        case BRIDGE_GEM:       typeName = "GEM";       break;
        case BRIDGE_LAB:       typeName = "LAB";       break;
        case BRIDGE_LOG:       typeName = "LOG";       break;
        case BRIDGE_ROPE:      typeName = "ROPE";      break;
        case BRIDGE_STONE:     typeName = "STONE";     break;
        case BRIDGE_STONE_RED: typeName = "STONE_RED"; break;
        case BRIDGE_VINE:      typeName = "VINE";      break;
    }
    AnimationUser::setAnimation("OBJECT_BRIDGE_PIECE_" + typeName);

    uint variations = currentAnimation->getAnimation()->frameCount;
    if (variations > 0) {
        currentAnimation->resetFrame(idx % variations);
    }

    isGravityAffected = false;
    isOneWay = true;
}

DynamicBridgePiece::~DynamicBridgePiece() {

}

bool DynamicBridgePiece::deactivate(int, int, int) {
    // Removal of bridge pieces is handled by the bridge event.
    return false;
}

Hitbox DynamicBridgePiece::getHitboxForParent() {
    return Hitbox(currentHitbox).extend(0, 4);
}

void DynamicBridgePiece::tryStandardMovement() {
    // The bridge piece doesn't move by itself.
}

DynamicBridge::DynamicBridge(std::shared_ptr<ActorAPI> api, double x, double y, unsigned int width,
    DynamicBridgeType type, unsigned int toughness)
    : CommonActor(api, x - 16.0, y - 16.0), originalY(y - 4.0), bridgeType(type), bridgeWidth(width),
    heightFactor((16.0 - toughness) * bridgeWidth) {
    loadResources("Object/Bridge");

    if ((uint)bridgeType > (uint)BRIDGE_LAB) {
        bridgeType = BRIDGE_ROPE;
    }

    auto& widthList = BRIDGE_PIECE_WIDTHS.value(bridgeType, { 16 });
    uint widthCovered = widthList[0] / 2;
    for (uint i = 0; (widthCovered <= width * 16) || (i * 16 < width); ++i) {
        auto piece_n = std::make_shared<DynamicBridgePiece>(api, x + widthCovered - 16, y - 20, type, i);
        api->addActor(piece_n);
        bridgePieces << piece_n;
        widthCovered += (widthList[i % widthList.size()] + widthList[(i + 1) % widthList.size()]) / 2;
    }

    isGravityAffected = false;
    updateHitbox();
}

DynamicBridge::~DynamicBridge() {

}

bool DynamicBridge::deactivate(int x, int y, int dist) {
    auto events = api->getGameEvents().lock();

    if ((std::abs(x - originTileX) > dist) || (std::abs(y - originTileY) > dist)) {
        if (events != nullptr) {
            events->deactivate(originTileX, originTileY);
        }

        for (int i = 0; i < bridgePieces.size(); ++i) {
            api->removeActor(bridgePieces.at(i));
        }
        api->removeActor(shared_from_this());
        return true;
    }
    return false;
}

void DynamicBridge::updateHitbox() {
    currentHitbox = Hitbox(posX, posY - 10.0, posX + bridgeWidth * 16.0, posY + 16.0);
}

void DynamicBridge::tickEvent() {
    auto collision = api->findCollisionActors(currentHitbox, shared_from_this());
    for (int j = 0; j < bridgePieces.size(); ++j) {
        collision.append(api->findCollisionActors(bridgePieces.at(j)->getHitboxForParent(), shared_from_this()));
    }

    bool found = false;
    for (int i = 0; i < collision.size(); ++i) {
        auto collisionPtr = collision.at(i).lock();
        if (collisionPtr == nullptr) {
            continue;
        }

        // TODO: This code only works with one player
        // PC is single player for now so that can be dealt with later
        auto p = std::dynamic_pointer_cast<Player>(collisionPtr);
        if (p != nullptr) {
            found = true;
            CoordinatePair coords = p->getPosition();
            int num = bridgePieces.size();

            // This marks which bridge piece is under the player and should be positioned
            // lower than any other piece of the bridge.
            double lowest = (coords.x - posX) / (bridgeWidth * 16.0) * num;

            // This marks the maximum drop in height.
            // At the middle of the bridge, this is purely the height factor,
            // which is simply (16 - bridge toughness) multiplied by the length of the bridge.
            // At other points, the height is scaled by an (arbitrarily chosen) power that
            // gives a nice curve.
            // Additionally, the drop is reduced based on the player position so that the
            // bridge seems to bend somewhat realistically instead of snapping from one position
            // to another.
            double drop = std::max(0.0, std::min(coords.y - posY + 32.0, (1.0 - std::pow(std::abs(2.0 * lowest / num - 1.0), 0.7)) * heightFactor));

            posY = std::min(originalY + drop, std::max(originalY, coords.y));

            // Update the position of each bridge piece.
            for (int j = 0; j < num; ++j) {
                auto piece = bridgePieces.at(j);
                coords.x = piece->getPosition().x;

                if (lowest > 0 && lowest < num) {
                    if (j <= lowest) {
                        coords.y = originalY + std::pow(j / lowest, 0.7) * drop;
                    } else {
                        coords.y = originalY + std::pow((num - 1 - j) / (num - 1 - lowest), 0.7) * drop;
                    }
                } else {
                    coords.y = originalY;
                }

                piece->moveInstantly(coords, true, true);
            }
        }

    }

    if (!found) {
        // The player was not touching the bridge, so reset all pieces to the default height.
        for (int j = 0; j < bridgePieces.size(); ++j) {
            CoordinatePair coords = bridgePieces.at(j)->getPosition();
            coords.y = originalY;
            bridgePieces.at(j)->moveInstantly(coords, true, true);
        }
        posY = originalY;
    }
}

// TODO: Maybe figure out a way to externalise this outside of the code later.
// Separate frame sizes kinda exist in Anims.j2a but they are not stored after
// the conversion and for 99% of the assets they would be useless cruft.
const QMap<DynamicBridgeType, QVector<uint>> DynamicBridge::BRIDGE_PIECE_WIDTHS = {
    { BRIDGE_GEM, { 14 }},
    { BRIDGE_LAB, { 14 }},
    { BRIDGE_LOG, { 13, 13, 13 }},
    { BRIDGE_STONE, { 15, 9, 10, 9, 15, 9, 15 }},
    { BRIDGE_STONE_RED, { 10, 11, 11, 12 }},
    { BRIDGE_ROPE, { 13, 13, 10, 13, 13, 12, 11 }},
    { BRIDGE_VINE, { 7, 7, 7, 7, 10, 7, 7, 7, 7 }}
};<commit_msg>Move the bridges a tad higher<commit_after>#include "Bridge.h"

#include <cmath>
#include "Player.h"
#include "../gamestate/ActorAPI.h"
#include "../gamestate/EventMap.h"

DynamicBridgePiece::DynamicBridgePiece(std::shared_ptr<ActorAPI> api, double x, double y, DynamicBridgeType type, uint idx)
    : SolidObject(api, x, y, false) {
    canBeFrozen = false;
    loadResources("Object/BridgePiece");

    QString typeName = "ROPE";
    switch (type) {
        case BRIDGE_GEM:       typeName = "GEM";       break;
        case BRIDGE_LAB:       typeName = "LAB";       break;
        case BRIDGE_LOG:       typeName = "LOG";       break;
        case BRIDGE_ROPE:      typeName = "ROPE";      break;
        case BRIDGE_STONE:     typeName = "STONE";     break;
        case BRIDGE_STONE_RED: typeName = "STONE_RED"; break;
        case BRIDGE_VINE:      typeName = "VINE";      break;
    }
    AnimationUser::setAnimation("OBJECT_BRIDGE_PIECE_" + typeName);

    uint variations = currentAnimation->getAnimation()->frameCount;
    if (variations > 0) {
        currentAnimation->resetFrame(idx % variations);
    }

    isGravityAffected = false;
    isOneWay = true;
}

DynamicBridgePiece::~DynamicBridgePiece() {

}

bool DynamicBridgePiece::deactivate(int, int, int) {
    // Removal of bridge pieces is handled by the bridge event.
    return false;
}

Hitbox DynamicBridgePiece::getHitboxForParent() {
    return Hitbox(currentHitbox).extend(0, 4);
}

void DynamicBridgePiece::tryStandardMovement() {
    // The bridge piece doesn't move by itself.
}

DynamicBridge::DynamicBridge(std::shared_ptr<ActorAPI> api, double x, double y, unsigned int width,
    DynamicBridgeType type, unsigned int toughness)
    : CommonActor(api, x - 16.0, y - 16.0), originalY(y - 8.0), bridgeType(type), bridgeWidth(width),
    heightFactor((16.0 - toughness) * bridgeWidth) {
    loadResources("Object/Bridge");

    if ((uint)bridgeType > (uint)BRIDGE_LAB) {
        bridgeType = BRIDGE_ROPE;
    }

    auto& widthList = BRIDGE_PIECE_WIDTHS.value(bridgeType, { 16 });
    uint widthCovered = widthList[0] / 2;
    for (uint i = 0; (widthCovered <= width * 16) || (i * 16 < width); ++i) {
        auto piece_n = std::make_shared<DynamicBridgePiece>(api, x + widthCovered - 16, y - 20, type, i);
        api->addActor(piece_n);
        bridgePieces << piece_n;
        widthCovered += (widthList[i % widthList.size()] + widthList[(i + 1) % widthList.size()]) / 2;
    }

    isGravityAffected = false;
    updateHitbox();
}

DynamicBridge::~DynamicBridge() {

}

bool DynamicBridge::deactivate(int x, int y, int dist) {
    auto events = api->getGameEvents().lock();

    if ((std::abs(x - originTileX) > dist) || (std::abs(y - originTileY) > dist)) {
        if (events != nullptr) {
            events->deactivate(originTileX, originTileY);
        }

        for (int i = 0; i < bridgePieces.size(); ++i) {
            api->removeActor(bridgePieces.at(i));
        }
        api->removeActor(shared_from_this());
        return true;
    }
    return false;
}

void DynamicBridge::updateHitbox() {
    currentHitbox = Hitbox(posX, posY - 10.0, posX + bridgeWidth * 16.0, posY + 16.0);
}

void DynamicBridge::tickEvent() {
    auto collision = api->findCollisionActors(currentHitbox, shared_from_this());
    for (int j = 0; j < bridgePieces.size(); ++j) {
        collision.append(api->findCollisionActors(bridgePieces.at(j)->getHitboxForParent(), shared_from_this()));
    }

    bool found = false;
    for (int i = 0; i < collision.size(); ++i) {
        auto collisionPtr = collision.at(i).lock();
        if (collisionPtr == nullptr) {
            continue;
        }

        // TODO: This code only works with one player
        // PC is single player for now so that can be dealt with later
        auto p = std::dynamic_pointer_cast<Player>(collisionPtr);
        if (p != nullptr) {
            found = true;
            CoordinatePair coords = p->getPosition();
            int num = bridgePieces.size();

            // This marks which bridge piece is under the player and should be positioned
            // lower than any other piece of the bridge.
            double lowest = (coords.x - posX) / (bridgeWidth * 16.0) * num;

            // This marks the maximum drop in height.
            // At the middle of the bridge, this is purely the height factor,
            // which is simply (16 - bridge toughness) multiplied by the length of the bridge.
            // At other points, the height is scaled by an (arbitrarily chosen) power that
            // gives a nice curve.
            // Additionally, the drop is reduced based on the player position so that the
            // bridge seems to bend somewhat realistically instead of snapping from one position
            // to another.
            double drop = std::max(0.0, std::min(coords.y - posY + 32.0, (1.0 - std::pow(std::abs(2.0 * lowest / num - 1.0), 0.7)) * heightFactor));

            posY = std::min(originalY + drop, std::max(originalY, coords.y));

            // Update the position of each bridge piece.
            for (int j = 0; j < num; ++j) {
                auto piece = bridgePieces.at(j);
                coords.x = piece->getPosition().x;

                if (lowest > 0 && lowest < num) {
                    if (j <= lowest) {
                        coords.y = originalY + std::pow(j / lowest, 0.7) * drop;
                    } else {
                        coords.y = originalY + std::pow((num - 1 - j) / (num - 1 - lowest), 0.7) * drop;
                    }
                } else {
                    coords.y = originalY;
                }

                piece->moveInstantly(coords, true, true);
            }
        }

    }

    if (!found) {
        // The player was not touching the bridge, so reset all pieces to the default height.
        for (int j = 0; j < bridgePieces.size(); ++j) {
            CoordinatePair coords = bridgePieces.at(j)->getPosition();
            coords.y = originalY;
            bridgePieces.at(j)->moveInstantly(coords, true, true);
        }
        posY = originalY;
    }
}

// TODO: Maybe figure out a way to externalise this outside of the code later.
// Separate frame sizes kinda exist in Anims.j2a but they are not stored after
// the conversion and for 99% of the assets they would be useless cruft.
const QMap<DynamicBridgeType, QVector<uint>> DynamicBridge::BRIDGE_PIECE_WIDTHS = {
    { BRIDGE_GEM, { 14 }},
    { BRIDGE_LAB, { 14 }},
    { BRIDGE_LOG, { 13, 13, 13 }},
    { BRIDGE_STONE, { 15, 9, 10, 9, 15, 9, 15 }},
    { BRIDGE_STONE_RED, { 10, 11, 11, 12 }},
    { BRIDGE_ROPE, { 13, 13, 10, 13, 13, 12, 11 }},
    { BRIDGE_VINE, { 7, 7, 7, 7, 10, 7, 7, 7, 7 }}
};<|endoftext|>


<commit_before>/*
 * fibers.cpp
 *
 * Created on: Jan 24, 2013
 * @author Ralph Schurade
 */
#include "fibers.h"

#include "../data/datasets/datasetfibers.h"
#include "../data/datasets/datasetscalar.h"
#include "../data/datasets/dataset3d.h"

#include <QSet>

#include <limits>
#include <math.h>

Fibers::Fibers( DatasetFibers* ds ) :
    m_dataset( ds ),
    m_nx( 1 ),
    m_ny( 1 ),
    m_nz( 1 ),
    m_dx( 1.0 ),
    m_dy( 1.0 ),
    m_dz( 1.0 ),
    m_blockSize( 1 )
{
}

Fibers::~Fibers()
{
}

DatasetFibers* Fibers::thinOut()
{
    float maxDistance = 1.0;
    bool merged = true;
    bool currentMerged = false;
    int iteration = 1;
    QVector< QVector< float > > fibs = m_dataset->getFibs();
    QVector< QVector< float > > mergedFibs;
    QVector< QVector< float > > unmergedFibs;

    while ( merged )
    {
        qDebug() << "iteration:" << iteration;
        ++iteration;
        qDebug() << fibs.size() << "fibers before merging";

        merged = false;
        QVector<bool>processed( fibs.size(), false );

        for ( int i = 0; i < fibs.size(); ++i )
        {
            if ( i % 1000 == 0 ) qDebug() << i << fibs.size() << mergedFibs.size() << unmergedFibs.size();
            currentMerged = false;
            QVector< float > currentFib = fibs[ i ];
            for( int k = i + 1; k < fibs.size(); ++k )
            {
                if ( currentFib.size() == fibs[k].size() )
                {
                    float dist = getFiberDist( currentFib, fibs[k] );
                    if ( dist < maxDistance )
                    {
                        mergedFibs.push_back( mergeFibs( currentFib, fibs[k]) );
                        merged = true;
                        currentMerged = true;
                        processed[k] = true;
                        break;
                    }
                }
            }
            if ( !currentMerged && !processed[i] )
            {
                unmergedFibs.push_back( currentFib );
            }
        }
        fibs = mergedFibs;
        mergedFibs.clear();
        qDebug() << fibs.size() + unmergedFibs.size() << "fibers after merging";
    }
    return new DatasetFibers( QDir( "new fibers" ), fibs + unmergedFibs );
}

QVector<float> Fibers::mergeFibs( QVector< float >& lhs, QVector< float >& rhs )
{
    QVector<float> out( lhs.size() );
    for ( int i = 0; i < lhs.size(); ++i )
    {
        out[i] = ( lhs[i] + rhs[i] ) / 2;
    }
    return out;
}

float Fibers::getFiberDist( QVector< float >& lhs, QVector< float >& rhs )
{
    float distSum = 0;
    float minSum;
    float lhsx;
    float lhsy;
    float lhsz;
    for ( int i = 0; i < lhs.size(); i += 3 )
    {
        minSum = std::numeric_limits<float>::max();
        lhsx = lhs.at( i );
        lhsy = lhs.at( i + 1 );
        lhsz = lhs.at( i + 2 );
        for( int k = 0; k < rhs.size(); k += 3 )
        {
            minSum = qMin( minSum, getDist( lhsx, lhsy, lhsz, rhs.at( i ), rhs.at( i + 1 ), rhs.at( i + 2 ) ) );
        }
        distSum += minSum;
    }
    distSum /= lhs.size();

    return distSum;
}

float Fibers::getDist( float x1, float y1, float z1, float x2, float y2, float z2 )
{
    float x = x1 - x2;
    float y = y1 - y2;
    float z = z1 - z2;
    return sqrt( x*x + y*y + z*z );
}

DatasetScalar* Fibers::tractDensity()
{
    m_nx = 160;
    m_ny = 200;
    m_nz = 160;
    m_dx = 1.0;
    m_dy = 1.0;
    m_dz = 1.0;
    m_blockSize = m_nx * m_ny * m_nz;
    QVector<float> data( m_blockSize, 0 );
    QVector< QVector< float > > fibs = m_dataset->getSelectedFibs();
    int x, y, z;
    for ( int i = 0; i < fibs.size(); ++i )
    {
        for( int k = 0; k < fibs[i].size() / 3; ++k )
        {
            x = fibs[i].at( k * 3     );
            y = fibs[i].at( k * 3 + 1 );
            z = fibs[i].at( k * 3 + 2 );
            ++data[ getID( x, y, z ) ];
        }
    }

    int dims[8] = { 3, 160, 200, 160, 1, 1, 1 };
    nifti_image* header = nifti_make_new_nim( dims, NIFTI_TYPE_FLOAT32, 1 );
    DatasetScalar* out = new DatasetScalar( QDir( "tract density" ), data, header );
    return out;
}

Dataset3D* Fibers::tractColor()
{
    m_nx = 320;
    m_ny = 400;
    m_nz = 320;
    m_dx = 0.5;
    m_dy = 0.5;
    m_dz = 0.5;
    m_blockSize = m_nx * m_ny * m_nz;
    QVector<QVector3D> data( m_blockSize );
    QVector<int> count( m_blockSize, 0 );
    QVector< QVector< float > > fibs = m_dataset->getSelectedFibs();
    float x, y, z;
    QSet<int> visited;
    int id = 0;
    for ( int i = 0; i < fibs.size(); ++i )
    {
        QVector<float> fib = fibs[i];
        visited.clear();

        QVector3D localColor( fabs( fib[0] - fib[3] ), fabs( fib[1] - fib[4] ), fabs( fib[2] - fib[5] ) );
        localColor.normalize();
        x = fib.at( 0 );
        y = fib.at( 1 );
        z = fib.at( 2 );
        id = getID( x, y, z );
        if ( !visited.contains( id) )
        {
            ++count[ id ];
            data[ id ] += localColor;
            visited.insert( id );
        }

        for ( int k = 1; k < fib.size() / 3 - 1; ++k )
        {
            QVector3D localColor( fabs( fib[k*3-3] - fib[k*3+3] ), fabs( fib[k*3-2] - fib[k*3+4] ), fabs( fib[k*3-1] - fib[k*3+5] ) );
            localColor.normalize();

            x = fib.at( k * 3 );
            y = fib.at( k * 3 + 1 );
            z = fib.at( k * 3 + 2 );
            id = getID( x, y, z );
            if ( !visited.contains( id) )
            {
                ++count[ id ];
                data[ id ] += localColor;
                visited.insert( id );
            }
        }

        int numFloats = fib.size();
        QVector3D localColor2( fabs( fib[numFloats-6] - fib[numFloats-3] ), fabs( fib[numFloats-5] - fib[numFloats-2] ), fabs( fib[numFloats-4] - fib[numFloats-1] ) );
        localColor2.normalize();

        x = fib.at( numFloats - 3 );
        y = fib.at( numFloats - 2 );
        z = fib.at( numFloats - 1 );
        id = getID( x, y, z );
        if ( !visited.contains( id) )
        {
            ++count[ id ];
            data[ id ] += localColor2;
            visited.insert( id );
        }
    }

    for ( int i = 0; i < m_blockSize; ++i )
    {
        data[i] /= count[i];
        count[i] = qMin( count[i], 10 );
    }
    float div;
    for ( int i = 0; i < m_blockSize; ++i )
    {
        div = ( (float)count[i] / 20. ) + 0.5;
        data[i] *= div;
    }

    int dims[8] = { 3, m_nx, m_ny, m_nz, 3, 1, 1 };
    nifti_image* header = nifti_make_new_nim( dims, NIFTI_TYPE_FLOAT32, 1 );
    header->dx = m_dx;
    header->dy = m_dy;
    header->dz = m_dz;
    Dataset3D* out = new Dataset3D( QDir( "tract color" ), data, header );
    return out;
}

DatasetFibers* Fibers::resample()
{
    QVector< QVector< float > > fibs = m_dataset->getFibs();
    QVector< QVector< float > > newFibs;

    for ( int i = 0; i < fibs.size();++i )
    {
        QVector<float> fib = fibs[i];
        QVector<float> newFib;

        if ( fib.size() > 6 )
        {
            for ( int k = 0; k < fib.size() / 3; k += 2 )
            {
                newFib.push_back( fib[k*3] );
                newFib.push_back( fib[k*3+1] );
                newFib.push_back( fib[k*3+2] );
            }

            if ( ( fib.size() / 3 ) % 2 == 1 )
            {
                newFib.push_back( fib[fib.size()-3] );
                newFib.push_back( fib[fib.size()-2] );
                newFib.push_back( fib[fib.size()-1] );
            }
            newFibs.push_back( newFib );
        }
    }

    return new DatasetFibers( QDir( "new fibers" ), newFibs );
}
<commit_msg>reworked tract density, fiber counts for voxel only once uses 10 steps between points<commit_after>/*
 * fibers.cpp
 *
 * Created on: Jan 24, 2013
 * @author Ralph Schurade
 */
#include "fibers.h"

#include "../data/datasets/datasetfibers.h"
#include "../data/datasets/datasetscalar.h"
#include "../data/datasets/dataset3d.h"

#include <QSet>
#include <QVector3D>

#include <limits>
#include <math.h>

Fibers::Fibers( DatasetFibers* ds ) :
    m_dataset( ds ),
    m_nx( 1 ),
    m_ny( 1 ),
    m_nz( 1 ),
    m_dx( 1.0 ),
    m_dy( 1.0 ),
    m_dz( 1.0 ),
    m_blockSize( 1 )
{
}

Fibers::~Fibers()
{
}

DatasetFibers* Fibers::thinOut()
{
    float maxDistance = 1.0;
    bool merged = true;
    bool currentMerged = false;
    int iteration = 1;
    QVector< QVector< float > > fibs = m_dataset->getFibs();
    QVector< QVector< float > > mergedFibs;
    QVector< QVector< float > > unmergedFibs;

    while ( merged )
    {
        qDebug() << "iteration:" << iteration;
        ++iteration;
        qDebug() << fibs.size() << "fibers before merging";

        merged = false;
        QVector<bool>processed( fibs.size(), false );

        for ( int i = 0; i < fibs.size(); ++i )
        {
            if ( i % 1000 == 0 ) qDebug() << i << fibs.size() << mergedFibs.size() << unmergedFibs.size();
            currentMerged = false;
            QVector< float > currentFib = fibs[ i ];
            for( int k = i + 1; k < fibs.size(); ++k )
            {
                if ( currentFib.size() == fibs[k].size() )
                {
                    float dist = getFiberDist( currentFib, fibs[k] );
                    if ( dist < maxDistance )
                    {
                        mergedFibs.push_back( mergeFibs( currentFib, fibs[k]) );
                        merged = true;
                        currentMerged = true;
                        processed[k] = true;
                        break;
                    }
                }
            }
            if ( !currentMerged && !processed[i] )
            {
                unmergedFibs.push_back( currentFib );
            }
        }
        fibs = mergedFibs;
        mergedFibs.clear();
        qDebug() << fibs.size() + unmergedFibs.size() << "fibers after merging";
    }
    return new DatasetFibers( QDir( "new fibers" ), fibs + unmergedFibs );
}

QVector<float> Fibers::mergeFibs( QVector< float >& lhs, QVector< float >& rhs )
{
    QVector<float> out( lhs.size() );
    for ( int i = 0; i < lhs.size(); ++i )
    {
        out[i] = ( lhs[i] + rhs[i] ) / 2;
    }
    return out;
}

float Fibers::getFiberDist( QVector< float >& lhs, QVector< float >& rhs )
{
    float distSum = 0;
    float minSum;
    float lhsx;
    float lhsy;
    float lhsz;
    for ( int i = 0; i < lhs.size(); i += 3 )
    {
        minSum = std::numeric_limits<float>::max();
        lhsx = lhs.at( i );
        lhsy = lhs.at( i + 1 );
        lhsz = lhs.at( i + 2 );
        for( int k = 0; k < rhs.size(); k += 3 )
        {
            minSum = qMin( minSum, getDist( lhsx, lhsy, lhsz, rhs.at( i ), rhs.at( i + 1 ), rhs.at( i + 2 ) ) );
        }
        distSum += minSum;
    }
    distSum /= lhs.size();

    return distSum;
}

float Fibers::getDist( float x1, float y1, float z1, float x2, float y2, float z2 )
{
    float x = x1 - x2;
    float y = y1 - y2;
    float z = z1 - z2;
    return sqrt( x*x + y*y + z*z );
}

DatasetScalar* Fibers::tractDensity()
{
    m_nx = 160;
    m_ny = 200;
    m_nz = 160;
    m_dx = 1.0;
    m_dy = 1.0;
    m_dz = 1.0;
    m_blockSize = m_nx * m_ny * m_nz;
    QVector<float> data( m_blockSize, 0 );
    QVector< QVector< float > > fibs = m_dataset->getSelectedFibs();
    int x, y, z;
    QVector3D p3;
    for ( int i = 0; i < fibs.size(); ++i )
    {
        QVector<float> fibdata( m_blockSize, 0 );

        for( int k = 0; k < ( fibs[i].size() / 3 ) - 1; ++k )
        {
            QVector3D p1( fibs[i].at( k * 3     ) + 0.5, fibs[i].at( k * 3 + 1 ) + 0.5, fibs[i].at( k * 3 + 2 ) + 0.5 );
            QVector3D p2( fibs[i].at( k * 3 + 3 ) + 0.5, fibs[i].at( k * 3 + 4 ) + 0.5, fibs[i].at( k * 3 + 5 ) + 0.5 );
            p2 = p2 - p1;
            p2.normalize();

            for ( int l = 0; l < 10; ++l )
            {
                p3 = p1 + ( ( (float)l / 10 ) * p2 ) ;
                x = p3.x();
                y = p3.y();
                z = p3.z();

                int id = getID( x, y, z );

                if ( fibdata[id] == 0 )
                {
                    ++fibdata[id];
                    ++data[id];
                }
            }
        }
    }

    int dims[8] = { 3, 160, 200, 160, 1, 1, 1 };
    nifti_image* header = nifti_make_new_nim( dims, NIFTI_TYPE_FLOAT32, 1 );
    DatasetScalar* out = new DatasetScalar( QDir( "tract density" ), data, header );
    return out;
}

Dataset3D* Fibers::tractColor()
{
    m_nx = 320;
    m_ny = 400;
    m_nz = 320;
    m_dx = 0.5;
    m_dy = 0.5;
    m_dz = 0.5;
    m_blockSize = m_nx * m_ny * m_nz;
    QVector<QVector3D> data( m_blockSize );
    QVector<int> count( m_blockSize, 0 );
    QVector< QVector< float > > fibs = m_dataset->getSelectedFibs();
    float x, y, z;
    QSet<int> visited;
    int id = 0;
    for ( int i = 0; i < fibs.size(); ++i )
    {
        QVector<float> fib = fibs[i];
        visited.clear();

        QVector3D localColor( fabs( fib[0] - fib[3] ), fabs( fib[1] - fib[4] ), fabs( fib[2] - fib[5] ) );
        localColor.normalize();
        x = fib.at( 0 );
        y = fib.at( 1 );
        z = fib.at( 2 );
        id = getID( x, y, z );
        if ( !visited.contains( id) )
        {
            ++count[ id ];
            data[ id ] += localColor;
            visited.insert( id );
        }

        for ( int k = 1; k < fib.size() / 3 - 1; ++k )
        {
            QVector3D localColor( fabs( fib[k*3-3] - fib[k*3+3] ), fabs( fib[k*3-2] - fib[k*3+4] ), fabs( fib[k*3-1] - fib[k*3+5] ) );
            localColor.normalize();

            x = fib.at( k * 3 );
            y = fib.at( k * 3 + 1 );
            z = fib.at( k * 3 + 2 );
            id = getID( x, y, z );
            if ( !visited.contains( id) )
            {
                ++count[ id ];
                data[ id ] += localColor;
                visited.insert( id );
            }
        }

        int numFloats = fib.size();
        QVector3D localColor2( fabs( fib[numFloats-6] - fib[numFloats-3] ), fabs( fib[numFloats-5] - fib[numFloats-2] ), fabs( fib[numFloats-4] - fib[numFloats-1] ) );
        localColor2.normalize();

        x = fib.at( numFloats - 3 );
        y = fib.at( numFloats - 2 );
        z = fib.at( numFloats - 1 );
        id = getID( x, y, z );
        if ( !visited.contains( id) )
        {
            ++count[ id ];
            data[ id ] += localColor2;
            visited.insert( id );
        }
    }

    for ( int i = 0; i < m_blockSize; ++i )
    {
        data[i] /= count[i];
        count[i] = qMin( count[i], 10 );
    }
    float div;
    for ( int i = 0; i < m_blockSize; ++i )
    {
        div = ( (float)count[i] / 20. ) + 0.5;
        data[i] *= div;
    }

    int dims[8] = { 3, m_nx, m_ny, m_nz, 3, 1, 1 };
    nifti_image* header = nifti_make_new_nim( dims, NIFTI_TYPE_FLOAT32, 1 );
    header->dx = m_dx;
    header->dy = m_dy;
    header->dz = m_dz;
    Dataset3D* out = new Dataset3D( QDir( "tract color" ), data, header );
    return out;
}

DatasetFibers* Fibers::resample()
{
    QVector< QVector< float > > fibs = m_dataset->getFibs();
    QVector< QVector< float > > newFibs;

    for ( int i = 0; i < fibs.size();++i )
    {
        QVector<float> fib = fibs[i];
        QVector<float> newFib;

        if ( fib.size() > 6 )
        {
            for ( int k = 0; k < fib.size() / 3; k += 2 )
            {
                newFib.push_back( fib[k*3] );
                newFib.push_back( fib[k*3+1] );
                newFib.push_back( fib[k*3+2] );
            }

            if ( ( fib.size() / 3 ) % 2 == 1 )
            {
                newFib.push_back( fib[fib.size()-3] );
                newFib.push_back( fib[fib.size()-2] );
                newFib.push_back( fib[fib.size()-1] );
            }
            newFibs.push_back( newFib );
        }
    }

    return new DatasetFibers( QDir( "new fibers" ), newFibs );
}
<|endoftext|>


<commit_before>#include <cmath>
#include <iostream>
#include <stdio.h>
#include <time.h>

#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
#include "DeviceDHT22.h"

#define DHT2_REFRESH_EVERY 300

DeviceDHT22::DeviceDHT22(Domoticz *domoticz, std::string &execCmd) : domo(domoticz), command(execCmd)
{
	tzset();
	this->timer = new boost::asio::deadline_timer(io);
	this->computeNextLaunch();
	this->threads.create_thread(boost::bind(&boost::asio::io_service::run, &this->io));
}

DeviceDHT22::~DeviceDHT22()
{
	this->threads.interrupt_all();
	delete this->timer;
}

void DeviceDHT22::computeNextLaunch()
{
	boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
	long currentMS = now.time_of_day().minutes() * 60L + now.time_of_day().seconds();

#ifdef DODEBUG
	std::cout << "DeviceDHT22::computeNextLaunch() - currentTime=" << to_simple_string(now.time_of_day());
#endif
	currentMS = DHT2_REFRESH_EVERY - (currentMS % DHT2_REFRESH_EVERY);
#ifdef DODEBUG
	std::cout << " waiting=" << currentMS << std::endl;
#endif
	this->timer->expires_from_now(boost::posix_time::seconds(currentMS));
	this->timer->async_wait(boost::bind(&DeviceDHT22::launch, this));
}

void DeviceDHT22::launch()
{
	FILE *fh;

	fh = popen(this->command.c_str(), "r");
	if (fh == nullptr)
		std::cerr << "popen() failed" << std::endl;
	else
	{
		boost::regex expression("^Humidity = (.+) % Temperature = (.+) \\*C.*$", boost::regex::perl);
		boost::cmatch what;
		char line[1024];
		int execReturn;

		while (fgets(line, sizeof(line), fh) != nullptr)
			if (boost::regex_match(line, what, expression))
			{
				float humidity = boost::lexical_cast<float>(what[1]);
				float temperature = boost::lexical_cast<float>(what[2]);

				this->updateData(temperature, humidity);
			}
		execReturn = pclose(fh);
#ifdef DODEBUG
		std::cout << "DeviceDHT22::launch() - Exec return: " << execReturn << std::endl;
#endif
	}
	this->computeNextLaunch();
}

void DeviceDHT22::updateData(float temperature, float humidity)
{
	sDomoticzDevice *dev = domo->getDeviceDTH22();
	time_t now = time(nullptr);

	if (dev != nullptr)
	{
		time_t diffDate = std::abs(now - dev->lastUpdate);
		float diffTemperature = std::abs(temperature - dev->temperature);
		float diffHumidity = std::abs(humidity - dev->humidity);

		if (diffDate >= 1200 || (diffHumidity <= 15.0 && diffTemperature <= 5.0))
			domo->setValuesDHT22(temperature, humidity);
		else
			std::cerr << "DeviceDHT22::updateData - invalid value : temperature=" << temperature << " d" << diffTemperature << " humdity=" << humidity << " d" << diffHumidity << std::endl;
	}
}
<commit_msg>Update device value update-to-date ! :)<commit_after>#include <cmath>
#include <iostream>
#include <stdio.h>
#include <time.h>

#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
#include "DeviceDHT22.h"

#define DHT2_REFRESH_EVERY 300

DeviceDHT22::DeviceDHT22(Domoticz *domoticz, std::string &execCmd) : domo(domoticz), command(execCmd)
{
	tzset();
	this->timer = new boost::asio::deadline_timer(io);
	this->computeNextLaunch();
	this->threads.create_thread(boost::bind(&boost::asio::io_service::run, &this->io));
}

DeviceDHT22::~DeviceDHT22()
{
	this->threads.interrupt_all();
	delete this->timer;
}

void DeviceDHT22::computeNextLaunch()
{
	boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
	long currentMS = now.time_of_day().minutes() * 60L + now.time_of_day().seconds();

#ifdef DODEBUG
	std::cout << "DeviceDHT22::computeNextLaunch() - currentTime=" << to_simple_string(now.time_of_day());
#endif
	currentMS = DHT2_REFRESH_EVERY - (currentMS % DHT2_REFRESH_EVERY);
#ifdef DODEBUG
	std::cout << " waiting=" << currentMS << std::endl;
#endif
	this->timer->expires_from_now(boost::posix_time::seconds(currentMS));
	this->timer->async_wait(boost::bind(&DeviceDHT22::launch, this));
}

void DeviceDHT22::launch()
{
	FILE *fh;

	fh = popen(this->command.c_str(), "r");
	if (fh == nullptr)
		std::cerr << "popen() failed" << std::endl;
	else
	{
		boost::regex expression("^Humidity = (.+) % Temperature = (.+) \\*C.*$", boost::regex::perl);
		boost::cmatch what;
		char line[1024];
		int execReturn;

		while (fgets(line, sizeof(line), fh) != nullptr)
			if (boost::regex_match(line, what, expression))
			{
				float humidity = boost::lexical_cast<float>(what[1]);
				float temperature = boost::lexical_cast<float>(what[2]);

				this->updateData(temperature, humidity);
			}
		execReturn = pclose(fh);
#ifdef DODEBUG
		std::cout << "DeviceDHT22::launch() - Exec return: " << execReturn << std::endl;
#endif
	}
	this->computeNextLaunch();
}

void DeviceDHT22::updateData(float temperature, float humidity)
{
	sDomoticzDevice *dev = domo->getDeviceDTH22();
	time_t now = time(nullptr);

	if (dev != nullptr)
	{
		time_t diffDate = std::abs(now - dev->lastUpdate);
		float diffTemperature = std::abs(temperature - dev->temperature);
		float diffHumidity = std::abs(humidity - dev->humidity);

		if (diffDate >= 1200 || (diffHumidity <= 15.0 && diffTemperature <= 5.0))
			if (domo->setValuesDHT22(temperature, humidity))
			{
				dev->lastUpdate = now;
				dev->humidity = humidity;
				dev->temperature = temperature;
			}
		else
			std::cerr << "DeviceDHT22::updateData - invalid value : temperature=" << temperature << " d" << diffTemperature << " humdity=" << humidity << " d" << diffHumidity << std::endl;
	}
}
<|endoftext|>


<commit_before><commit_msg>Don't forcibly set our network state to NETWORK_LOADING after media initializes.<commit_after><|endoftext|>


<commit_before>#line 2 "togo/game/gfx/types.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Graphics types.
@ingroup lib_game_types
@ingroup lib_game_gfx
*/

#pragma once

#include <togo/game/config.hpp>
#include <togo/core/types.hpp>
#include <togo/core/utility/traits.hpp>
#include <togo/core/utility/utility.hpp>
#include <togo/core/math/types.hpp>
#include <togo/core/collection/types.hpp>
#include <togo/core/hash/hash.hpp>
#include <togo/core/serialization/types.hpp>
#include <togo/game/resource/types.hpp>

#include <initializer_list>

namespace togo {

namespace game {
namespace gfx {

/**
	@addtogroup lib_game_gfx_display
	@{
*/

/// Graphics configuration flags.
enum class DisplayConfigFlags : unsigned {
	/// Empty flag.
	none = 0,
	/// Double-buffered display.
	double_buffered = 1 << 0,
};

/// Graphics configuration.
///
/// If either msaa_num_buffers or msaa_num_samples are 0, MSAA is
/// disabled.
struct DisplayConfig {
	struct ColorBits {
		unsigned red;
		unsigned green;
		unsigned blue;
		unsigned alpha;
	};

	/// Color buffer bits.
	gfx::DisplayConfig::ColorBits color_bits;

	/// Depth buffer bits.
	/// If this is 0, the depth buffer should be assumed unavailable.
	unsigned depth_bits;

	/// Stencil buffer bits.
	/// If this is 0, the stencil buffer should be assumed unavailable.
	unsigned stencil_bits;

	/// Number of MSAA buffers.
	unsigned msaa_num_buffers;
	/// Number of MSAA samples.
	unsigned msaa_num_samples;

	/// Miscellaneous flags.
	gfx::DisplayConfigFlags flags;
};

/// Display flags.
enum class DisplayFlags : unsigned {
	/// Empty flag.
	none = 0,
	/// Center window.
	centered = 1 << 0,
	/// Border-less window.
	borderless = 1 << 1,
	/// Full-screen window.
	fullscreen = 1 << 2,
	/// Re-sizable window.
	resizable = 1 << 3,

	owned_by_input_buffer = 1 << 4,
};

/// Display swap modes.
enum class DisplaySwapMode : unsigned {
	/// No screen synchronization.
	immediate = 0,

	/// Wait for at least one refresh cycle before swapping.
	wait_refresh,
};

/// Graphics display.
struct Display;

/** @} */ // end of doc-group lib_game_gfx_display

/**
	@addtogroup lib_game_gfx_renderer
	@{
*/

// TODO: Documentation & configuration
#define TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS 16
#define TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND 16

#define TOGO_GFX_NODE_NUM_COMMANDS 1024
#define TOGO_GFX_NODE_BUFFER_SIZE 8192

#define TOGO_GFX_KEY_SEQ_BITS 9
#define TOGO_GFX_KEY_SEQ_MAX (1ul << TOGO_GFX_KEY_SEQ_BITS)
#define TOGO_GFX_KEY_SEQ_MASK (TOGO_GFX_KEY_SEQ_MAX - 1)

#define TOGO_GFX_KEY_USER_BITS (64ul - TOGO_GFX_KEY_SEQ_BITS)
#define TOGO_GFX_KEY_USER_MASK ((1ul << TOGO_GFX_KEY_USER_BITS) - 1)

#define TOGO_GFX_CONFIG_NUM_PIPES 8
#define TOGO_GFX_CONFIG_NUM_VIEWPORTS 8
#define TOGO_GFX_PIPE_NUM_LAYERS 32
#define TOGO_GFX_LAYER_NUM_GENERATORS 16

#define TOGO_GFX_NUM_BUFFERS 2048
#define TOGO_GFX_NUM_BUFFER_BINDINGS 2048
#define TOGO_GFX_NUM_TEXTURES 2048
#define TOGO_GFX_NUM_UNIFORMS 64
#define TOGO_GFX_NUM_SHADERS 128
#define TOGO_GFX_NUM_NODES 4

/// Buffer data binding mode.
enum class BufferDataBinding : unsigned {
	/// Buffer data never changes.
	fixed,
	/// Buffer data changes frequently.
	dynamic,

	NUM
};

enum : u32 {
	/// Null resource ID.
	ID_VALUE_NULL = 0,
};

/** @cond INTERNAL */
struct Buffer;
struct BufferBinding;
struct Texture;
struct Uniform;
struct Shader;

template<class /*R*/>
struct ResourceID {
	u32 _value;

	bool valid() const {
		return _value != gfx::ID_VALUE_NULL;
	}
};
/** @endcond */ // INTERNAL

/// Buffer ID.
using BufferID = gfx::ResourceID<gfx::Buffer>;

/// Buffer binding ID.
using BufferBindingID = gfx::ResourceID<gfx::BufferBinding>;

/// Texture ID.
using TextureID = gfx::ResourceID<gfx::Texture>;

/// Uniform ID.
using UniformID = gfx::ResourceID<gfx::Uniform>;

/// Shader ID.
using ShaderID = gfx::ResourceID<gfx::Shader>;

struct GeneratorDef;
struct GeneratorUnit;

struct RenderConfig;
struct RenderObject;
struct RenderNode;
struct Camera;

/// Renderer.
struct Renderer;

/// Renderer type.
using RendererType = hash32;

/// Parameter block name hash.
using ParamBlockNameHash = hash32;

/// Generator name hash.
using GeneratorNameHash = hash32;

/// Viewport name hash.
using ViewportNameHash = hash32;

namespace hash_literals {

/// Parameter block name hash literal.
inline constexpr ParamBlockNameHash
operator"" _param_block_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Generator name hash literal.
inline constexpr GeneratorNameHash
operator"" _generator_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Viewport name hash literal.
inline constexpr ViewportNameHash
operator"" _viewport_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

} // namespace hash_literals

using namespace hash_literals;

/// Renderer types.
enum : RendererType {
	/// OpenGL renderer.
	RENDERER_TYPE_OPENGL = "opengl"_hash32,
};

/// Parameter block names.
enum : ParamBlockNameHash {
	/// Null name.
	PB_NAME_NULL = ""_param_block_name,
};

/// Generator names.
enum : GeneratorNameHash {
	/// Null name.
	GEN_NAME_NULL = ""_generator_name,
};

/// Viewport names.
enum : ViewportNameHash {
	/// Null name.
	VIEWPORT_NAME_NULL = ""_viewport_name,
};

/// Configured generator.
struct GeneratorUnit {
	/// GeneratorUnit exec() function.
	using exec_func_type = void (
		gfx::GeneratorUnit const& unit,
		gfx::RenderNode& node,
		gfx::RenderObject const* objects_begin,
		gfx::RenderObject const* objects_end
	);

	gfx::GeneratorNameHash name_hash;
	void* data;

	/// Execute the generator.
	///
	/// objects_begin and objects_end are nullptr for
	/// non-Process Generators.
	exec_func_type* func_exec;
};

/// Generator definition.
struct GeneratorDef {
	/// GeneratorDef destroy() function.
	using destroy_func_type = void (
		gfx::GeneratorDef const& def,
		gfx::Renderer* renderer
	);

	/// GeneratorUnit read() function.
	using read_unit_func_type = void (
		gfx::GeneratorDef const& def,
		gfx::Renderer* renderer,
		BinaryInputSerializer& ser,
		gfx::GeneratorUnit& unit
	);

	gfx::GeneratorNameHash name_hash;
	void* data;

	/// Destroy the definition data.
	destroy_func_type* func_destroy;
	/// Read a GeneratorUnit.
	read_unit_func_type* func_read_unit;
};

/// Primitive data type.
enum class Primitive : unsigned {
	u8, u16, u32,
	f32, f64,

	NUM
};

/// Integral primitive data type.
enum class IntegerPrimitive : unsigned {
	u8, u16, u32,

	NUM
};

/// Unpacked vertex attribute.
struct VertexAttrib {
	gfx::Primitive type;
	unsigned num_components;
	bool normalize_fixed;
};

// TODO: Encode attribute data to an integer to save memory
// TODO: Utilize C++14 constexpr features for compile-time construction
/// Vertex format.
struct VertexFormat {
	u32_fast _num_attribs;
	u32_fast _stride;
	gfx::VertexAttrib _attribs[TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS];
	u8 _offsets[TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS];

	inline /*constexpr*/ VertexFormat(
		std::initializer_list<gfx::VertexAttrib> const ilist
	) noexcept
		: _num_attribs(0)
		, _stride(0)
		, _attribs()
		, _offsets()
	{
		static constexpr unsigned const
		attrib_type_size[]{
			sizeof(u8), sizeof(u16), sizeof(u32),
			sizeof(f32), sizeof(f64),
		};
		for (auto const& attrib : ilist) {
			_attribs[_num_attribs] = attrib;
			_offsets[_num_attribs] = _stride;
			_stride += attrib_type_size[unsigned_cast(attrib.type)] * attrib.num_components;
			++_num_attribs;
		}
	}
};

/// Index binding.
struct IndexBinding {
	gfx::BufferID id;
	gfx::IntegerPrimitive type;
};

/// Vertex binding.
struct VertexBinding {
	gfx::BufferID id;
	gfx::VertexFormat const* format;
	u32 offset;
};

/// Parameter block binding.
struct ParamBlockBinding {
	gfx::BufferID id;
	u32 offset;
	u32 size;
};

/// Parameter block definition.
struct ParamBlockDef {
	u32 index;
	ParamBlockNameHash name_hash;
	StringRef name;
};

/// Shader stage.
struct ShaderStage {
	enum class Type : u32 {
		vertex = 0,
		fragment,

		NUM
	};

	Type type;
	FixedArray<StringRef, 24> sources;
};

/// Shader specification (creation).
struct ShaderSpec {
	FixedArray<gfx::ParamBlockDef, TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND> fixed_param_blocks;
	FixedArray<gfx::ParamBlockDef, TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND> draw_param_blocks;
	FixedArray<gfx::ShaderStage, unsigned_cast(gfx::ShaderStage::Type::NUM)> stages;
};

/// Shader definition (resource).
struct ShaderDef {
	/// Properties.
	enum : u32 {
		TYPE_MASK = 0x0F,
		TYPE_PRELUDE = 1 << 0,
		TYPE_UNIT = 1 << 1,

		LANG_MASK = 0xF0,
		LANG_GLSL = 1 << 4,

		// stage sources indices + param block names + size of data
		NUM_INDICES
			= unsigned_cast(gfx::ShaderStage::Type::NUM)
			+ 32
			+ 1
		,
		IDX_PARAM_NAMES = unsigned_cast(gfx::ShaderStage::Type::NUM),
	};

	u32 properties;
	// String blob containing all sources in sequence and all param
	// block names. Shared source starts at 0. fragment and vertex source are
	// indexed by members.
	Array<char> data;
	FixedArray<ResourceNameHash, 8> prelude;
	FixedArray<u32, NUM_INDICES> data_offsets;
	// gfx::ParamBlockDef::name is patched to .data during serialization
	FixedArray<gfx::ParamBlockDef, TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND> fixed_param_blocks;
	FixedArray<gfx::ParamBlockDef, TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND> draw_param_blocks;

	ShaderDef() = delete;
	ShaderDef(ShaderDef const&) = delete;
	ShaderDef& operator=(ShaderDef const&) = delete;

	~ShaderDef() = default;
	ShaderDef(ShaderDef&&) = default;
	ShaderDef& operator=(ShaderDef&&) = default;

	ShaderDef(
		Allocator& allocator
	)
		: properties(0)
		, data(allocator)
		, prelude()
		, data_offsets()
		, fixed_param_blocks()
		, draw_param_blocks()
	{}
};

/// Pipe layer.
struct Layer {
	enum class Order : u32 {
		back_front,
		front_back,
	};

	hash32 name_hash;
	FixedArray<hash32, 4> rts;
	hash32 dst;
	Order order;
	u32 seq_base;
	FixedArray<gfx::GeneratorUnit, TOGO_GFX_LAYER_NUM_GENERATORS> layout;
	FixedArray<char, 32> name;
};

/// Render pipe.
struct Pipe {
	hash32 name_hash;
	FixedArray<gfx::Layer, TOGO_GFX_PIPE_NUM_LAYERS> layers;
	FixedArray<char, 32> name;
};

/// Render viewport.
struct Viewport {
	// TODO: resources
	gfx::ViewportNameHash name_hash;
	u32 pipe;
	hash32 output_rt;
	hash32 output_dst;
	FixedArray<char, 32> name;
};

/// Render config.
struct RenderConfig {
	// TODO: shared_resources
	FixedArray<gfx::Viewport, TOGO_GFX_CONFIG_NUM_VIEWPORTS> viewports;
	FixedArray<gfx::Pipe, TOGO_GFX_CONFIG_NUM_PIPES> pipes;
};

/// Render object.
struct RenderObject {
	Mat4x4 transform;
	gfx::BufferBindingID binding;
};

/// Render command key.
struct CmdKey {
	u64 key;
	void* data;
};

/// Render node.
struct RenderNode {
	u64 sequence;
	unsigned num_commands;
	unsigned buffer_size;
	gfx::CmdKey keys[TOGO_GFX_NODE_NUM_COMMANDS];
	u8 buffer[TOGO_GFX_NODE_BUFFER_SIZE];
};

// TODO: Move to component
/// Camera.
struct Camera {};

/** @} */ // end of doc-group lib_game_gfx_renderer

} // namespace gfx
} // namespace game

/** @cond INTERNAL */
template<>
struct enable_enum_bitwise_ops<game::gfx::DisplayConfigFlags> : true_type {};

template<>
struct enable_enum_bitwise_ops<game::gfx::DisplayFlags> : true_type {};
/** @endcond */ // INTERNAL

} // namespace togo
<commit_msg>lib/game/gfx: use TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND when defining ShaderDef::NUM_INDICES.<commit_after>#line 2 "togo/game/gfx/types.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Graphics types.
@ingroup lib_game_types
@ingroup lib_game_gfx
*/

#pragma once

#include <togo/game/config.hpp>
#include <togo/core/types.hpp>
#include <togo/core/utility/traits.hpp>
#include <togo/core/utility/utility.hpp>
#include <togo/core/math/types.hpp>
#include <togo/core/collection/types.hpp>
#include <togo/core/hash/hash.hpp>
#include <togo/core/serialization/types.hpp>
#include <togo/game/resource/types.hpp>

#include <initializer_list>

namespace togo {

namespace game {
namespace gfx {

/**
	@addtogroup lib_game_gfx_display
	@{
*/

/// Graphics configuration flags.
enum class DisplayConfigFlags : unsigned {
	/// Empty flag.
	none = 0,
	/// Double-buffered display.
	double_buffered = 1 << 0,
};

/// Graphics configuration.
///
/// If either msaa_num_buffers or msaa_num_samples are 0, MSAA is
/// disabled.
struct DisplayConfig {
	struct ColorBits {
		unsigned red;
		unsigned green;
		unsigned blue;
		unsigned alpha;
	};

	/// Color buffer bits.
	gfx::DisplayConfig::ColorBits color_bits;

	/// Depth buffer bits.
	/// If this is 0, the depth buffer should be assumed unavailable.
	unsigned depth_bits;

	/// Stencil buffer bits.
	/// If this is 0, the stencil buffer should be assumed unavailable.
	unsigned stencil_bits;

	/// Number of MSAA buffers.
	unsigned msaa_num_buffers;
	/// Number of MSAA samples.
	unsigned msaa_num_samples;

	/// Miscellaneous flags.
	gfx::DisplayConfigFlags flags;
};

/// Display flags.
enum class DisplayFlags : unsigned {
	/// Empty flag.
	none = 0,
	/// Center window.
	centered = 1 << 0,
	/// Border-less window.
	borderless = 1 << 1,
	/// Full-screen window.
	fullscreen = 1 << 2,
	/// Re-sizable window.
	resizable = 1 << 3,

	owned_by_input_buffer = 1 << 4,
};

/// Display swap modes.
enum class DisplaySwapMode : unsigned {
	/// No screen synchronization.
	immediate = 0,

	/// Wait for at least one refresh cycle before swapping.
	wait_refresh,
};

/// Graphics display.
struct Display;

/** @} */ // end of doc-group lib_game_gfx_display

/**
	@addtogroup lib_game_gfx_renderer
	@{
*/

// TODO: Documentation & configuration
#define TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS 16
#define TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND 16

#define TOGO_GFX_NODE_NUM_COMMANDS 1024
#define TOGO_GFX_NODE_BUFFER_SIZE 8192

#define TOGO_GFX_KEY_SEQ_BITS 9
#define TOGO_GFX_KEY_SEQ_MAX (1ul << TOGO_GFX_KEY_SEQ_BITS)
#define TOGO_GFX_KEY_SEQ_MASK (TOGO_GFX_KEY_SEQ_MAX - 1)

#define TOGO_GFX_KEY_USER_BITS (64ul - TOGO_GFX_KEY_SEQ_BITS)
#define TOGO_GFX_KEY_USER_MASK ((1ul << TOGO_GFX_KEY_USER_BITS) - 1)

#define TOGO_GFX_CONFIG_NUM_PIPES 8
#define TOGO_GFX_CONFIG_NUM_VIEWPORTS 8
#define TOGO_GFX_PIPE_NUM_LAYERS 32
#define TOGO_GFX_LAYER_NUM_GENERATORS 16

#define TOGO_GFX_NUM_BUFFERS 2048
#define TOGO_GFX_NUM_BUFFER_BINDINGS 2048
#define TOGO_GFX_NUM_TEXTURES 2048
#define TOGO_GFX_NUM_UNIFORMS 64
#define TOGO_GFX_NUM_SHADERS 128
#define TOGO_GFX_NUM_NODES 4

/// Buffer data binding mode.
enum class BufferDataBinding : unsigned {
	/// Buffer data never changes.
	fixed,
	/// Buffer data changes frequently.
	dynamic,

	NUM
};

enum : u32 {
	/// Null resource ID.
	ID_VALUE_NULL = 0,
};

/** @cond INTERNAL */
struct Buffer;
struct BufferBinding;
struct Texture;
struct Uniform;
struct Shader;

template<class /*R*/>
struct ResourceID {
	u32 _value;

	bool valid() const {
		return _value != gfx::ID_VALUE_NULL;
	}
};
/** @endcond */ // INTERNAL

/// Buffer ID.
using BufferID = gfx::ResourceID<gfx::Buffer>;

/// Buffer binding ID.
using BufferBindingID = gfx::ResourceID<gfx::BufferBinding>;

/// Texture ID.
using TextureID = gfx::ResourceID<gfx::Texture>;

/// Uniform ID.
using UniformID = gfx::ResourceID<gfx::Uniform>;

/// Shader ID.
using ShaderID = gfx::ResourceID<gfx::Shader>;

struct GeneratorDef;
struct GeneratorUnit;

struct RenderConfig;
struct RenderObject;
struct RenderNode;
struct Camera;

/// Renderer.
struct Renderer;

/// Renderer type.
using RendererType = hash32;

/// Parameter block name hash.
using ParamBlockNameHash = hash32;

/// Generator name hash.
using GeneratorNameHash = hash32;

/// Viewport name hash.
using ViewportNameHash = hash32;

namespace hash_literals {

/// Parameter block name hash literal.
inline constexpr ParamBlockNameHash
operator"" _param_block_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Generator name hash literal.
inline constexpr GeneratorNameHash
operator"" _generator_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Viewport name hash literal.
inline constexpr ViewportNameHash
operator"" _viewport_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

} // namespace hash_literals

using namespace hash_literals;

/// Renderer types.
enum : RendererType {
	/// OpenGL renderer.
	RENDERER_TYPE_OPENGL = "opengl"_hash32,
};

/// Parameter block names.
enum : ParamBlockNameHash {
	/// Null name.
	PB_NAME_NULL = ""_param_block_name,
};

/// Generator names.
enum : GeneratorNameHash {
	/// Null name.
	GEN_NAME_NULL = ""_generator_name,
};

/// Viewport names.
enum : ViewportNameHash {
	/// Null name.
	VIEWPORT_NAME_NULL = ""_viewport_name,
};

/// Configured generator.
struct GeneratorUnit {
	/// GeneratorUnit exec() function.
	using exec_func_type = void (
		gfx::GeneratorUnit const& unit,
		gfx::RenderNode& node,
		gfx::RenderObject const* objects_begin,
		gfx::RenderObject const* objects_end
	);

	gfx::GeneratorNameHash name_hash;
	void* data;

	/// Execute the generator.
	///
	/// objects_begin and objects_end are nullptr for
	/// non-Process Generators.
	exec_func_type* func_exec;
};

/// Generator definition.
struct GeneratorDef {
	/// GeneratorDef destroy() function.
	using destroy_func_type = void (
		gfx::GeneratorDef const& def,
		gfx::Renderer* renderer
	);

	/// GeneratorUnit read() function.
	using read_unit_func_type = void (
		gfx::GeneratorDef const& def,
		gfx::Renderer* renderer,
		BinaryInputSerializer& ser,
		gfx::GeneratorUnit& unit
	);

	gfx::GeneratorNameHash name_hash;
	void* data;

	/// Destroy the definition data.
	destroy_func_type* func_destroy;
	/// Read a GeneratorUnit.
	read_unit_func_type* func_read_unit;
};

/// Primitive data type.
enum class Primitive : unsigned {
	u8, u16, u32,
	f32, f64,

	NUM
};

/// Integral primitive data type.
enum class IntegerPrimitive : unsigned {
	u8, u16, u32,

	NUM
};

/// Unpacked vertex attribute.
struct VertexAttrib {
	gfx::Primitive type;
	unsigned num_components;
	bool normalize_fixed;
};

// TODO: Encode attribute data to an integer to save memory
// TODO: Utilize C++14 constexpr features for compile-time construction
/// Vertex format.
struct VertexFormat {
	u32_fast _num_attribs;
	u32_fast _stride;
	gfx::VertexAttrib _attribs[TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS];
	u8 _offsets[TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS];

	inline /*constexpr*/ VertexFormat(
		std::initializer_list<gfx::VertexAttrib> const ilist
	) noexcept
		: _num_attribs(0)
		, _stride(0)
		, _attribs()
		, _offsets()
	{
		static constexpr unsigned const
		attrib_type_size[]{
			sizeof(u8), sizeof(u16), sizeof(u32),
			sizeof(f32), sizeof(f64),
		};
		for (auto const& attrib : ilist) {
			_attribs[_num_attribs] = attrib;
			_offsets[_num_attribs] = _stride;
			_stride += attrib_type_size[unsigned_cast(attrib.type)] * attrib.num_components;
			++_num_attribs;
		}
	}
};

/// Index binding.
struct IndexBinding {
	gfx::BufferID id;
	gfx::IntegerPrimitive type;
};

/// Vertex binding.
struct VertexBinding {
	gfx::BufferID id;
	gfx::VertexFormat const* format;
	u32 offset;
};

/// Parameter block binding.
struct ParamBlockBinding {
	gfx::BufferID id;
	u32 offset;
	u32 size;
};

/// Parameter block definition.
struct ParamBlockDef {
	u32 index;
	ParamBlockNameHash name_hash;
	StringRef name;
};

/// Shader stage.
struct ShaderStage {
	enum class Type : u32 {
		vertex = 0,
		fragment,

		NUM
	};

	Type type;
	FixedArray<StringRef, 24> sources;
};

/// Shader specification (creation).
struct ShaderSpec {
	FixedArray<gfx::ParamBlockDef, TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND> fixed_param_blocks;
	FixedArray<gfx::ParamBlockDef, TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND> draw_param_blocks;
	FixedArray<gfx::ShaderStage, unsigned_cast(gfx::ShaderStage::Type::NUM)> stages;
};

/// Shader definition (resource).
struct ShaderDef {
	/// Properties.
	enum : u32 {
		TYPE_MASK = 0x0F,
		TYPE_PRELUDE = 1 << 0,
		TYPE_UNIT = 1 << 1,

		LANG_MASK = 0xF0,
		LANG_GLSL = 1 << 4,

		// stage sources indices + param block names + size of data
		NUM_INDICES
			= unsigned_cast(gfx::ShaderStage::Type::NUM)
			+ TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND // fixed
			+ TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND // draw
			+ 1
		,
		IDX_PARAM_NAMES = unsigned_cast(gfx::ShaderStage::Type::NUM),
	};

	u32 properties;
	// String blob containing all sources in sequence and all param
	// block names. Shared source starts at 0. fragment and vertex source are
	// indexed by members.
	Array<char> data;
	FixedArray<ResourceNameHash, 8> prelude;
	FixedArray<u32, NUM_INDICES> data_offsets;
	// gfx::ParamBlockDef::name is patched to .data during serialization
	FixedArray<gfx::ParamBlockDef, TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND> fixed_param_blocks;
	FixedArray<gfx::ParamBlockDef, TOGO_GFX_NUM_PARAM_BLOCKS_BY_KIND> draw_param_blocks;

	ShaderDef() = delete;
	ShaderDef(ShaderDef const&) = delete;
	ShaderDef& operator=(ShaderDef const&) = delete;

	~ShaderDef() = default;
	ShaderDef(ShaderDef&&) = default;
	ShaderDef& operator=(ShaderDef&&) = default;

	ShaderDef(
		Allocator& allocator
	)
		: properties(0)
		, data(allocator)
		, prelude()
		, data_offsets()
		, fixed_param_blocks()
		, draw_param_blocks()
	{}
};

/// Pipe layer.
struct Layer {
	enum class Order : u32 {
		back_front,
		front_back,
	};

	hash32 name_hash;
	FixedArray<hash32, 4> rts;
	hash32 dst;
	Order order;
	u32 seq_base;
	FixedArray<gfx::GeneratorUnit, TOGO_GFX_LAYER_NUM_GENERATORS> layout;
	FixedArray<char, 32> name;
};

/// Render pipe.
struct Pipe {
	hash32 name_hash;
	FixedArray<gfx::Layer, TOGO_GFX_PIPE_NUM_LAYERS> layers;
	FixedArray<char, 32> name;
};

/// Render viewport.
struct Viewport {
	// TODO: resources
	gfx::ViewportNameHash name_hash;
	u32 pipe;
	hash32 output_rt;
	hash32 output_dst;
	FixedArray<char, 32> name;
};

/// Render config.
struct RenderConfig {
	// TODO: shared_resources
	FixedArray<gfx::Viewport, TOGO_GFX_CONFIG_NUM_VIEWPORTS> viewports;
	FixedArray<gfx::Pipe, TOGO_GFX_CONFIG_NUM_PIPES> pipes;
};

/// Render object.
struct RenderObject {
	Mat4x4 transform;
	gfx::BufferBindingID binding;
};

/// Render command key.
struct CmdKey {
	u64 key;
	void* data;
};

/// Render node.
struct RenderNode {
	u64 sequence;
	unsigned num_commands;
	unsigned buffer_size;
	gfx::CmdKey keys[TOGO_GFX_NODE_NUM_COMMANDS];
	u8 buffer[TOGO_GFX_NODE_BUFFER_SIZE];
};

// TODO: Move to component
/// Camera.
struct Camera {};

/** @} */ // end of doc-group lib_game_gfx_renderer

} // namespace gfx
} // namespace game

/** @cond INTERNAL */
template<>
struct enable_enum_bitwise_ops<game::gfx::DisplayConfigFlags> : true_type {};

template<>
struct enable_enum_bitwise_ops<game::gfx::DisplayFlags> : true_type {};
/** @endcond */ // INTERNAL

} // namespace togo
<|endoftext|>


<commit_before>//
//  Exponent.cpp
//  Calculator
//
//  Created by Gavin Scheele on 3/27/14.
//  Copyright (c) 2014 Gavin Scheele. All rights reserved.
//

#include "Exponential.h"

Exponential::Exponential(Expression* base, Rational* exponent){
    this->type = "exponential";
    this->base = base;
    this->exponent = exponent;
    this->exde = new Integer(exponent->getDenominator());
    if (exde->getValue() != 1) {
    	//if the denominator of the exponent is not 1, make the base a root of the denominator, then setting the denominator equal to 1
    	Integer* baseAsInteger = (Integer *) base;
        base = new nthRoot(exde->getValue(), baseAsInteger->getValue(), 1);
        Integer* one = new Integer(1);
        exponent->setDenominator(one);
    }
    this->exnu = new Integer(exponent->getNumerator());
    if (canExponentiate()) {
    	this* = exponentiate();                 //cant assign this
    }
}
Exponential::~Exponential(){

}

bool Exponential::canExponentiate() {
    if(base->type == "euler"){
        return false;

    }else if(base->type == "exponential"){
	Exponential* ex = (Exponential *) base;
	this->exponent->multiply(ex->getExponent());
	Integer* numSum = new Integer (1);
	ex->getExponent()->setNumerator(numSum);
        return false;
        // false is returned because the base itself would have already been exponentiated if it were possible

    }else if(base->type == "integer"){
        return true;

    }else if(base->type == "logarithm"){
        return false;

    }else if(base->type == "nthRoot"){
	nthRoot* nr = (nthRoot *) base;
	Rational* r = new Rational(this->exponent->getNumerator(), nr->getRoot()*this->exponent->getDenominator());
	//makes a new exponent, multiplying the denominator by the root, allowing the root to be simplified to one
	this->exponent = r;
	nr->setRoot(1);
	return false;

    }else if(base->type == "pi"){
        return false;

    }else if(base->type == "rational"){
        Rational* r = (Rational *) base;
        if (r->geteNumerator()->type == "integer" && r->geteDenominator()->type == "integer") {
          Exponential* nu = new Exponential(r->geteNumerator(), this->exponent);
          r->setNumerator(nu);
          Exponential* de = new Exponential(r->geteDenominator(), this->exponent);
          r->setDenominator(de);
        }

    }else{
        cout << "type not recognized" << endl;
    }
    return false;
}

void Exponential::exponentiate(){

    Expression* constantBase = base;
    if (this->exponent->getNumerator()==0) {
        Integer* oneInt = new Integer(1);
        Rational* oneRat = new Rational(1, 1);
       this->exponent=oneRat;
       this->base=oneInt;

    }
    bool toFlip = false;
    if (exnu->getValue()<0) {
	    exnu->setValue(exnu->getValue()*-1);
            toFlip = true;
            //handles negative exponents
    }
    while (exponent->getNumerator()>1)
    	{
        base->multiply(constantBase);
        exponent->setNumerator(exponent->getNumerator()-1);
    }
    if (toFlip) {
    	Rational* mouse = new Rational(oneInt, base);
    	base = mouse;
    }

}

Expression* Exponential::add(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){
	Exponential* ex = (Exponential *) a;
	if (ex->getBase()==this->base) {
		if (ex->getExponent()==this->exponent) {
			Integer* two = new Integer(2);
			this->multiply(two);
		}
	}

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Exponential::subtract(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){
	Exponential* ex = (Exponential *) a;
	if (ex->getBase()==this->base) {
		if (ex->getExponent()==this->exponent) {
			Integer* zero = new Integer(0);
			this->multiply(zero);
		}
	}
    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Exponential::multiply(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){
	Exponential* ex = (Exponential *) a;
	if (this->base == ex->getBase()) {
		this->exponent->add(ex->getExponent());
	}

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){
	Rational* r = (Rational *) r;
	r->setNumerator(r->getNumerator()->multiply(this*));        //
	return r;

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Exponential::divide(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){
	Exponential* ex = (Exponential *) a;
	if (this->base == ex->getBase()) {
		this->exponent->subtract(ex->getExponent());
	}

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){
	Rational* r = (Rational *) r;
	r->setDenominator(r->getDenominator->multiply(this*));      //
	return r;

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}

Rational* Exponential::getExponent() {
    return exponent;
}

Expression* Exponential::getBase() {
    return base;
}

Integer* Exponential::getExnu() {
	return exnu;
}

Integer* Exponential::getExde() {
	return exde;
}

void Exponential::setExnu(Integer* n) {
	exnu = n;
}

void Exponential::setExde(Integer* n) {
	exde = n;
}

void Exponential::setExponent(Rational* e) {
    exponent = e;
}

void Exponential::setBase(Expression* e) {
    base = e;
}

string Exponential::toString() {
  //  string str = base + "^" + exponent;
    stringstream str;
    str << base << "^" << exponent;
    return str.str();
}

ostream& Exponential::print(std::ostream& output) const{
    output << this->base << this->exponent; //overload cout so that it makes sense
    return output;
}
<commit_msg>added Exponential comments for errors<commit_after>//
//  Exponent.cpp
//  Calculator
//
//  Created by Gavin Scheele on 3/27/14.
//  Copyright (c) 2014 Gavin Scheele. All rights reserved.
//

#include "Exponential.h"

Exponential::Exponential(Expression* base, Rational* exponent){
    this->type = "exponential";
    this->base = base;
    this->exponent = exponent;
    this->exde = new Integer(exponent->getDenominator());
    if (exde->getValue() != 1) {
    	//if the denominator of the exponent is not 1, make the base a root of the denominator, then setting the denominator equal to 1
    	Integer* baseAsInteger = (Integer *) base;
        base = new nthRoot(exde->getValue(), baseAsInteger->getValue(), 1);
        Integer* one = new Integer(1);
        exponent->setDenominator(one);
    }
    this->exnu = new Integer(exponent->getNumerator());
    if (canExponentiate()) {
    	this* = exponentiate();                 //cant assign this
    }
}
Exponential::~Exponential(){

}

bool Exponential::canExponentiate() {
    if(base->type == "euler"){
        return false;

    }else if(base->type == "exponential"){
	Exponential* ex = (Exponential *) base;
	this->exponent->multiply(ex->getExponent());
	Integer* numSum = new Integer (1);
	ex->getExponent()->setNumerator(numSum);
        return false;
        // false is returned because the base itself would have already been exponentiated if it were possible

    }else if(base->type == "integer"){
        return true;

    }else if(base->type == "logarithm"){
        return false;

    }else if(base->type == "nthRoot"){
	nthRoot* nr = (nthRoot *) base;
	Rational* r = new Rational(this->exponent->getNumerator(), nr->getRoot()*this->exponent->getDenominator());
	//makes a new exponent, multiplying the denominator by the root, allowing the root to be simplified to one
	this->exponent = r;
	nr->setRoot(1);
	return false;

    }else if(base->type == "pi"){
        return false;

    }else if(base->type == "rational"){
        Rational* r = (Rational *) base;
        if (r->geteNumerator()->type == "integer" && r->geteDenominator()->type == "integer") {
          Exponential* nu = new Exponential(r->geteNumerator(), this->exponent);
          r->setNumerator(nu);
          Exponential* de = new Exponential(r->geteDenominator(), this->exponent);
          r->setDenominator(de);
        }

    }else{
        cout << "type not recognized" << endl;
    }
    return false;
}

void Exponential::exponentiate(){

    Expression* constantBase = base;
    if (this->exponent->getNumerator()==0) {
        Integer* oneInt = new Integer(1);
        Rational* oneRat = new Rational(1, 1);
       this->exponent=oneRat;
       this->base=oneInt;

    }
    bool toFlip = false;
    if (exnu->getValue()<0) {
	    exnu->setValue(exnu->getValue()*-1);
            toFlip = true;
            //handles negative exponents
    }
    while (exponent->getNumerator()>1)
    	{
        base->multiply(constantBase);
        exponent->setNumerator(exponent->getNumerator()-1);     //Error: cannot initialize a parameter of type 'Expression *' with an rvalue of type 'int'
    }
    if (toFlip) {
    	Rational* mouse = new Rational(oneInt, base);       //oneInt is not declared
    	base = mouse;
    }

}

Expression* Exponential::add(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){
	Exponential* ex = (Exponential *) a;
	if (ex->getBase()==this->base) {
		if (ex->getExponent()==this->exponent) {
			Integer* two = new Integer(2);
			this->multiply(two);
		}
	}

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Exponential::subtract(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){
	Exponential* ex = (Exponential *) a;
	if (ex->getBase()==this->base) {
		if (ex->getExponent()==this->exponent) {
			Integer* zero = new Integer(0);
			this->multiply(zero);
		}
	}
    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Exponential::multiply(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){
	Exponential* ex = (Exponential *) a;
	if (this->base == ex->getBase()) {
		this->exponent->add(ex->getExponent());
	}

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){
	Rational* r = (Rational *) r;
	r->setNumerator(r->getNumerator()->multiply(this*));        //Error: expected expression
	return r;

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}
Expression* Exponential::divide(Expression* a){
    if(a->type == "euler"){

    }else if(a->type == "exponential"){
	Exponential* ex = (Exponential *) a;
	if (this->base == ex->getBase()) {
		this->exponent->subtract(ex->getExponent());
	}

    }else if(a->type == "integer"){

    }else if(a->type == "logarithm"){

    }else if(a->type == "nthRoot"){

    }else if(a->type == "pi"){

    }else if(a->type == "rational"){
	Rational* r = (Rational *) r;
	r->setDenominator(r->getDenominator()->multiply(this*));      //Error: member reference type 'int' is not a pointer
	return r;

    }else{
        cout << "type not recognized" << endl;
    }
    return this;
}

Rational* Exponential::getExponent() {
    return exponent;
}

Expression* Exponential::getBase() {
    return base;
}

Integer* Exponential::getExnu() {
	return exnu;
}

Integer* Exponential::getExde() {
	return exde;
}

void Exponential::setExnu(Integer* n) {
	exnu = n;
}

void Exponential::setExde(Integer* n) {
	exde = n;
}

void Exponential::setExponent(Rational* e) {
    exponent = e;
}

void Exponential::setBase(Expression* e) {
    base = e;
}

string Exponential::toString() {
  //  string str = base + "^" + exponent;
    stringstream str;
    str << base << "^" << exponent;
    return str.str();
}

ostream& Exponential::print(std::ostream& output) const{
    output << this->base << this->exponent; //overload cout so that it makes sense
    return output;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "application.h"
#include "commandlinefrontend.h"
#include "parser/commandlineparser.h"

#include <qbs.h>
#include <logging/consolelogger.h>
#include <tools/hostosinfo.h>

#include <QProcess>
#include <QTimer>

using namespace qbs;

static bool tryToRunTool(const QStringList &arguments, int &exitCode)
{
    if (arguments.isEmpty())
        return false;
    qputenv("PATH", QCoreApplication::applicationDirPath().toLocal8Bit()
            + HostOsInfo::pathListSeparator().toLatin1() + QByteArray(qgetenv("PATH")));
    QStringList subProcessArgs = arguments;
    const QString subProcess = subProcessArgs.takeFirst();
    if (subProcess.startsWith(QLatin1Char('-')))
        return false;
    exitCode = QProcess::execute(QLatin1String("qbs-") + subProcess, subProcessArgs);
    return exitCode != -2;
}

int main(int argc, char *argv[])
{
    ConsoleLogger cl;

    Application app(argc, argv);
    QStringList arguments = app.arguments();
    arguments.removeFirst();

    int toolExitCode = 0;
    if (tryToRunTool(arguments, toolExitCode))
        return toolExitCode;

    CommandLineParser parser;
    if (!parser.parseCommandLine(arguments))
        return EXIT_FAILURE;

    if (parser.command() == HelpCommandType) {
        parser.printHelp();
        return 0;
    }

    CommandLineFrontend clFrontend(parser);
    app.setCommandLineFrontend(&clFrontend);
    QTimer::singleShot(0, &clFrontend, SLOT(start()));
    return app.exec();
}
<commit_msg>catch all exceptions in command line frontend<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "application.h"
#include "commandlinefrontend.h"
#include "parser/commandlineparser.h"

#include <qbs.h>
#include <logging/consolelogger.h>
#include <tools/hostosinfo.h>

#include <QProcess>
#include <QTimer>

using namespace qbs;

static bool tryToRunTool(const QStringList &arguments, int &exitCode)
{
    if (arguments.isEmpty())
        return false;
    qputenv("PATH", QCoreApplication::applicationDirPath().toLocal8Bit()
            + HostOsInfo::pathListSeparator().toLatin1() + QByteArray(qgetenv("PATH")));
    QStringList subProcessArgs = arguments;
    const QString subProcess = subProcessArgs.takeFirst();
    if (subProcess.startsWith(QLatin1Char('-')))
        return false;
    exitCode = QProcess::execute(QLatin1String("qbs-") + subProcess, subProcessArgs);
    return exitCode != -2;
}

int main(int argc, char *argv[])
{
    ConsoleLogger cl;

    try {
        Application app(argc, argv);
        QStringList arguments = app.arguments();
        arguments.removeFirst();

        int toolExitCode = 0;
        if (tryToRunTool(arguments, toolExitCode))
            return toolExitCode;

        CommandLineParser parser;
        if (!parser.parseCommandLine(arguments))
            return EXIT_FAILURE;

        if (parser.command() == HelpCommandType) {
            parser.printHelp();
            return 0;
        }

        CommandLineFrontend clFrontend(parser);
        app.setCommandLineFrontend(&clFrontend);
        QTimer::singleShot(0, &clFrontend, SLOT(start()));
        return app.exec();
    } catch (const Error &error) {
        qbsError() << error.toString();
        return EXIT_FAILURE;
    }
}
<|endoftext|>