Merge remote-tracking branch 'refs/remotes/origin/master' into culling
This commit is contained in:
@@ -11,10 +11,22 @@ namespace Nz
|
||||
void HardwareInfoImpl::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4])
|
||||
{
|
||||
#if defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
|
||||
asm volatile ("cpuid" // Besoin d'être volatile ?
|
||||
: "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
|
||||
: "a" (functionId), "c" (subFunctionId)); // input
|
||||
// https://en.wikipedia.org/wiki/CPUID
|
||||
asm volatile(
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
"pushq %%rbx \n\t" // save %rbx
|
||||
#else
|
||||
"pushl %%ebx \n\t" // save %ebx
|
||||
#endif
|
||||
"cpuid \n\t"
|
||||
"movl %%ebx ,%[ebx] \n\t" // write the result into output var
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
"popq %%rbx \n\t"
|
||||
#else
|
||||
"popl %%ebx \n\t"
|
||||
#endif
|
||||
: "=a"(registers[0]), [ebx] "=r"(registers[1]), "=c"(registers[2]), "=d"(registers[3])
|
||||
: "a"(functionId), "c" (subFunctionId));
|
||||
#else
|
||||
NazaraInternalError("Cpuid has been called although it is not supported");
|
||||
#endif
|
||||
@@ -22,7 +34,7 @@ namespace Nz
|
||||
|
||||
unsigned int HardwareInfoImpl::GetProcessorCount()
|
||||
{
|
||||
// Plus simple (et plus portable) que de passer par le CPUID
|
||||
// Simpler (and more portable) than using CPUID
|
||||
return sysconf(_SC_NPROCESSORS_CONF);
|
||||
}
|
||||
|
||||
@@ -37,7 +49,7 @@ namespace Nz
|
||||
bool HardwareInfoImpl::IsCpuidSupported()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
return true; // Toujours supporté sur un processeur 64 bits
|
||||
return true; // cpuid is always supported on x64 arch
|
||||
#else
|
||||
#if defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
int supported;
|
||||
|
||||
@@ -44,14 +44,19 @@ namespace Nz
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Reads characters in the stream
|
||||
* \brief Reads a line from the stream
|
||||
*
|
||||
* Reads the stream until a line separator or the end of the stream is found.
|
||||
*
|
||||
* If lineSize does not equal zero, it represents the maximum character count to be read from the stream.
|
||||
*
|
||||
* \param lineSize Maximum number of characters to read, or zero for no limit
|
||||
*
|
||||
* \return Line containing characters
|
||||
*
|
||||
* \param lineSize Number of characters to read, if lineSize is 0, read as much as possible
|
||||
*
|
||||
* \remark Produces a NazaraWarning if cursor position could not be reset
|
||||
* \remark With the text stream option, "\r\n" is treated as "\n"
|
||||
* \remark The line separator character is not returned as part of the string
|
||||
*/
|
||||
|
||||
String Stream::ReadLine(unsigned int lineSize)
|
||||
{
|
||||
String line;
|
||||
@@ -71,19 +76,33 @@ namespace Nz
|
||||
if (ptr)
|
||||
{
|
||||
std::ptrdiff_t pos = ptr - buffer;
|
||||
|
||||
if (m_streamOptions & StreamOption_Text && pos > 0 && buffer[pos - 1] == '\r')
|
||||
line.Append(buffer, pos - 1);
|
||||
else
|
||||
line.Append(buffer, pos);
|
||||
if (ptr != buffer)
|
||||
{
|
||||
if (m_streamOptions & StreamOption_Text && buffer[pos - 1] == '\r')
|
||||
line.Append(buffer, pos - 1);
|
||||
else
|
||||
line.Append(buffer, pos);
|
||||
}
|
||||
|
||||
if (!SetCursorPos(GetCursorPos() - readSize + pos + 1))
|
||||
NazaraWarning("Failed to reset cursos pos");
|
||||
NazaraWarning("Failed to reset cursor pos");
|
||||
|
||||
break;
|
||||
if (!line.IsEmpty())
|
||||
break;
|
||||
}
|
||||
else
|
||||
line.Append(buffer, readSize);
|
||||
{
|
||||
std::size_t length = readSize;
|
||||
if (m_streamOptions & StreamOption_Text && buffer[length - 1] == '\r')
|
||||
{
|
||||
if (!SetCursorPos(GetCursorPos() - 1))
|
||||
NazaraWarning("Failed to reset cursor pos");
|
||||
|
||||
length--;
|
||||
}
|
||||
|
||||
line.Append(buffer, length);
|
||||
}
|
||||
}
|
||||
while (readSize == bufferSize);
|
||||
}
|
||||
|
||||
@@ -3461,6 +3461,7 @@ namespace Nz
|
||||
p--;
|
||||
|
||||
*p = '\0';
|
||||
newString->size = p - str;
|
||||
|
||||
return String(std::move(newString));
|
||||
}
|
||||
@@ -4552,7 +4553,7 @@ namespace Nz
|
||||
|
||||
String& String::operator=(String&& string) noexcept
|
||||
{
|
||||
return Set(string);
|
||||
return Set(std::move(string));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -5851,7 +5852,7 @@ namespace Nz
|
||||
if (!m_sharedString.unique())
|
||||
{
|
||||
auto newSharedString = std::make_shared<SharedString>(GetSize(), GetCapacity());
|
||||
if (!discardContent)
|
||||
if (!discardContent && newSharedString->size > 0)
|
||||
std::memcpy(newSharedString->string.get(), GetConstBuffer(), GetSize()+1);
|
||||
|
||||
m_sharedString = std::move(newSharedString);
|
||||
@@ -5878,7 +5879,7 @@ namespace Nz
|
||||
*/
|
||||
bool Serialize(SerializationContext& context, const String& string)
|
||||
{
|
||||
if (!Serialize<UInt32>(context, string.GetSize()))
|
||||
if (!Serialize(context, UInt32(string.GetSize())))
|
||||
return false;
|
||||
|
||||
return context.stream->Write(string.GetConstBuffer(), string.GetSize()) == string.GetSize();
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Nz
|
||||
{
|
||||
ConditionVariableImpl::ConditionVariableImpl()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
InitializeConditionVariable(&m_cv);
|
||||
#else
|
||||
m_count = 0;
|
||||
@@ -21,7 +21,7 @@ namespace Nz
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !NAZARA_CORE_WINDOWS_VISTA
|
||||
#if !NAZARA_CORE_WINDOWS_NT6
|
||||
ConditionVariableImpl::~ConditionVariableImpl()
|
||||
{
|
||||
CloseHandle(m_events[BROADCAST]);
|
||||
@@ -31,7 +31,7 @@ namespace Nz
|
||||
|
||||
void ConditionVariableImpl::Signal()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
WakeConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
@@ -41,7 +41,7 @@ namespace Nz
|
||||
|
||||
void ConditionVariableImpl::SignalAll()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
WakeAllConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
@@ -56,8 +56,8 @@ namespace Nz
|
||||
|
||||
bool ConditionVariableImpl::Wait(MutexImpl* mutex, UInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
return SleepConditionVariableCS(&m_cv, &mutex->m_criticalSection, timeout);
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
return SleepConditionVariableCS(&m_cv, &mutex->m_criticalSection, timeout) == TRUE;
|
||||
#else
|
||||
m_count++;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Nz
|
||||
{
|
||||
public:
|
||||
ConditionVariableImpl();
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
~ConditionVariableImpl() = default;
|
||||
#else
|
||||
~ConditionVariableImpl();
|
||||
@@ -34,7 +34,7 @@ namespace Nz
|
||||
bool Wait(MutexImpl* mutex, UInt32 timeout);
|
||||
|
||||
private:
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
CONDITION_VARIABLE m_cv;
|
||||
#else
|
||||
enum
|
||||
|
||||
@@ -22,10 +22,22 @@ namespace Nz
|
||||
// Visual propose une fonction intrinsèque pour le cpuid
|
||||
__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
|
||||
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
|
||||
asm volatile ("cpuid" // Besoin d'être volatile ?
|
||||
: "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
|
||||
: "a" (functionId), "c" (subFunctionId)); // input
|
||||
// https://en.wikipedia.org/wiki/CPUID
|
||||
asm volatile(
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
"pushq %%rbx \n\t" // save %rbx
|
||||
#else
|
||||
"pushl %%ebx \n\t" // save %ebx
|
||||
#endif
|
||||
"cpuid \n\t"
|
||||
"movl %%ebx ,%[ebx] \n\t" // write the result into output var
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
"popq %%rbx \n\t"
|
||||
#else
|
||||
"popl %%ebx \n\t"
|
||||
#endif
|
||||
: "=a"(registers[0]), [ebx] "=r"(registers[1]), "=c"(registers[2]), "=d"(registers[3]) // output
|
||||
: "a"(functionId), "c" (subFunctionId)); // input
|
||||
#else
|
||||
NazaraInternalError("Cpuid has been called although it is not supported");
|
||||
#endif
|
||||
@@ -33,7 +45,7 @@ namespace Nz
|
||||
|
||||
unsigned int HardwareInfoImpl::GetProcessorCount()
|
||||
{
|
||||
// Plus simple (et plus portable) que de passer par le CPUID
|
||||
// Simpler (and more portable) than using CPUID
|
||||
SYSTEM_INFO infos;
|
||||
GetNativeSystemInfo(&infos);
|
||||
|
||||
@@ -52,7 +64,7 @@ namespace Nz
|
||||
bool HardwareInfoImpl::IsCpuidSupported()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
return true; // Toujours supporté sur un processeur 64 bits
|
||||
return true; // cpuid is always supported on x64 arch
|
||||
#else
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
int supported;
|
||||
|
||||
@@ -469,6 +469,8 @@ namespace Nz
|
||||
Renderer::DrawPrimitivesInstanced(renderedBillboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -769,6 +771,7 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
}
|
||||
instances.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,6 +291,7 @@ namespace Nz
|
||||
declaration->EnableComponent(ParticleComponent_Normal, ComponentType_Float3, NazaraOffsetOf(ParticleStruct_Billboard, normal));
|
||||
declaration->EnableComponent(ParticleComponent_Position, ComponentType_Float3, NazaraOffsetOf(ParticleStruct_Billboard, position));
|
||||
declaration->EnableComponent(ParticleComponent_Rotation, ComponentType_Float1, NazaraOffsetOf(ParticleStruct_Billboard, rotation));
|
||||
declaration->EnableComponent(ParticleComponent_Size, ComponentType_Float2, NazaraOffsetOf(ParticleStruct_Billboard, size));
|
||||
declaration->EnableComponent(ParticleComponent_Velocity, ComponentType_Float3, NazaraOffsetOf(ParticleStruct_Billboard, velocity));
|
||||
|
||||
NazaraAssert(declaration->GetStride() == sizeof(ParticleStruct_Billboard), "Invalid stride for declaration ParticleLayout_Billboard");
|
||||
|
||||
@@ -68,7 +68,12 @@ namespace Nz
|
||||
|
||||
std::size_t x = tileIndex % m_mapSize.x;
|
||||
std::size_t y = tileIndex / m_mapSize.x;
|
||||
Vector3f tileLeftCorner(x * m_tileSize.x, y * -m_tileSize.y, 0.f);
|
||||
|
||||
Vector3f tileLeftCorner;
|
||||
if (m_isometricModeEnabled)
|
||||
tileLeftCorner.Set(x * m_tileSize.x + m_tileSize.x/2.f * (y % 2), y/2.f * -m_tileSize.y, 0.f);
|
||||
else
|
||||
tileLeftCorner.Set(x * m_tileSize.x, y * -m_tileSize.y, 0.f);
|
||||
|
||||
*colorPtr++ = tile.color;
|
||||
*posPtr++ = instanceData->transformMatrix.Transform(tileLeftCorner);
|
||||
|
||||
112
src/Nazara/Network/Linux/SocketPollerImpl.cpp
Normal file
112
src/Nazara/Network/Linux/SocketPollerImpl.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Network/Linux/SocketPollerImpl.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <Nazara/Network/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
SocketPollerImpl::SocketPollerImpl()
|
||||
{
|
||||
m_handle = epoll_create1(0);
|
||||
}
|
||||
|
||||
SocketPollerImpl::~SocketPollerImpl()
|
||||
{
|
||||
close(m_handle);
|
||||
}
|
||||
|
||||
void SocketPollerImpl::Clear()
|
||||
{
|
||||
m_activeSockets.clear();
|
||||
m_sockets.clear();
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::IsReady(SocketHandle socket) const
|
||||
{
|
||||
return m_activeSockets.count(socket) != 0;
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
|
||||
{
|
||||
return m_sockets.count(socket) != 0;
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
|
||||
{
|
||||
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
||||
|
||||
epoll_event event;
|
||||
event.events = EPOLLIN;
|
||||
event.data.fd = socket;
|
||||
|
||||
if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &event) != 0)
|
||||
{
|
||||
NazaraError("Failed to add socket to epoll structure (errno " + String::Number(errno) + ": " + Error::GetLastSystemError() + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sockets.insert(socket);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SocketPollerImpl::UnregisterSocket(SocketHandle socket)
|
||||
{
|
||||
NazaraAssert(IsRegistered(socket), "Socket is not registered");
|
||||
|
||||
m_activeSockets.erase(socket);
|
||||
m_sockets.erase(socket);
|
||||
|
||||
if (epoll_ctl(m_handle, EPOLL_CTL_DEL, socket, nullptr) != 0)
|
||||
NazaraWarning("An error occured while removing socket from epoll structure (errno " + String::Number(errno) + ": " + Error::GetLastSystemError() + ')');
|
||||
}
|
||||
|
||||
int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
|
||||
{
|
||||
int activeSockets;
|
||||
|
||||
// Reset status of sockets
|
||||
m_events.resize(m_sockets.size());
|
||||
std::memset(m_events.data(), 0, m_events.size() * sizeof(epoll_event));
|
||||
|
||||
activeSockets = epoll_wait(m_handle, m_events.data(), static_cast<int>(m_events.size()), static_cast<int>(msTimeout));
|
||||
if (activeSockets == -1)
|
||||
{
|
||||
if (error)
|
||||
*error = SocketImpl::TranslateErrnoToResolveError(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_activeSockets.clear();
|
||||
if (activeSockets > 0U)
|
||||
{
|
||||
int socketCount = activeSockets;
|
||||
for (int i = 0; i < socketCount; ++i)
|
||||
{
|
||||
if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
|
||||
{
|
||||
m_activeSockets.insert(m_events[i].data.fd);
|
||||
if (m_events[i].events & EPOLLERR)
|
||||
NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll with EPOLLERR status");
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll without EPOLLIN (events: 0x" + String::Number(m_events[i].events, 16) + ')');
|
||||
activeSockets--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return activeSockets;
|
||||
}
|
||||
}
|
||||
42
src/Nazara/Network/Linux/SocketPollerImpl.hpp
Normal file
42
src/Nazara/Network/Linux/SocketPollerImpl.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
#define NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
#include <Nazara/Network/SocketHandle.hpp>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class SocketPollerImpl
|
||||
{
|
||||
public:
|
||||
SocketPollerImpl();
|
||||
~SocketPollerImpl();
|
||||
|
||||
void Clear();
|
||||
|
||||
bool IsReady(SocketHandle socket) const;
|
||||
bool IsRegistered(SocketHandle socket) const;
|
||||
|
||||
bool RegisterSocket(SocketHandle socket);
|
||||
void UnregisterSocket(SocketHandle socket);
|
||||
|
||||
int Wait(UInt64 msTimeout, SocketError* error);
|
||||
|
||||
private:
|
||||
std::unordered_set<SocketHandle> m_activeSockets;
|
||||
std::unordered_set<SocketHandle> m_sockets;
|
||||
std::vector<epoll_event> m_events;
|
||||
int m_handle;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
@@ -2,6 +2,11 @@
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_IPADDRESSIMPL_HPP
|
||||
#define NAZARA_IPADDRESSIMPL_HPP
|
||||
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -30,3 +35,5 @@ namespace Nz
|
||||
static ResolveError TranslateEAIErrorToResolveError(int error);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_IPADDRESSIMPL_HPP
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <Nazara/Network/Debug.hpp>
|
||||
@@ -397,6 +398,23 @@ namespace Nz
|
||||
return IpAddressImpl::FromSockAddr(reinterpret_cast<sockaddr*>(nameBuffer.data()));
|
||||
}
|
||||
|
||||
int SocketImpl::Poll(PollSocket* fdarray, std::size_t nfds, int timeout, SocketError* error)
|
||||
{
|
||||
NazaraAssert(fdarray && nfds > 0, "Invalid fdarray");
|
||||
|
||||
static_assert(sizeof(PollSocket) == sizeof(pollfd), "PollSocket size must match WSAPOLLFD size");
|
||||
|
||||
int result = poll(reinterpret_cast<pollfd*>(fdarray), static_cast<nfds_t>(nfds), timeout);
|
||||
if (result < 0)
|
||||
{
|
||||
if (error)
|
||||
*error = TranslateErrnoToResolveError(GetLastErrorCode());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error)
|
||||
{
|
||||
|
||||
@@ -2,12 +2,26 @@
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SOCKETIMPL_HPP
|
||||
#define NAZARA_SOCKETIMPL_HPP
|
||||
|
||||
#include <Nazara/Network/SocketHandle.hpp>
|
||||
#include <Nazara/Network/Enums.hpp>
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
|
||||
#define NAZARA_NETWORK_POLL_SUPPORT 1
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
struct PollSocket
|
||||
{
|
||||
SocketHandle fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
|
||||
class SocketImpl
|
||||
{
|
||||
public:
|
||||
@@ -42,6 +56,8 @@ namespace Nz
|
||||
static IpAddress QueryPeerAddress(SocketHandle handle, SocketError* error = nullptr);
|
||||
static IpAddress QuerySocketAddress(SocketHandle handle, SocketError* error = nullptr);
|
||||
|
||||
static int Poll(PollSocket* fdarray, std::size_t nfds, int timeout, SocketError* error);
|
||||
|
||||
static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error);
|
||||
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);
|
||||
|
||||
@@ -66,3 +82,5 @@ namespace Nz
|
||||
static socketID s_socket;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_SOCKETIMPL_HPP
|
||||
93
src/Nazara/Network/Posix/SocketPollerImpl.cpp
Normal file
93
src/Nazara/Network/Posix/SocketPollerImpl.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Network/Posix/SocketPollerImpl.hpp>
|
||||
#include <poll.h>
|
||||
#include <Nazara/Network/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
void SocketPollerImpl::Clear()
|
||||
{
|
||||
m_activeSockets.clear();
|
||||
m_allSockets.clear();
|
||||
m_sockets.clear();
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::IsReady(SocketHandle socket) const
|
||||
{
|
||||
return m_activeSockets.count(socket) != 0;
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
|
||||
{
|
||||
return m_allSockets.count(socket) != 0;
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
|
||||
{
|
||||
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
||||
|
||||
PollSocket entry = {
|
||||
socket,
|
||||
POLLRDNORM,
|
||||
0
|
||||
};
|
||||
|
||||
m_allSockets[socket] = m_sockets.size();
|
||||
m_sockets.emplace_back(entry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SocketPollerImpl::UnregisterSocket(SocketHandle socket)
|
||||
{
|
||||
NazaraAssert(IsRegistered(socket), "Socket is not registered");
|
||||
|
||||
if (m_sockets.size() > 1U)
|
||||
{
|
||||
// Instead of using vector::erase, let's move the last element to the now unoccupied position
|
||||
std::size_t entry = m_allSockets[socket];
|
||||
|
||||
// Get the last element and update it's position
|
||||
const PollSocket& lastElement = m_sockets.back();
|
||||
m_allSockets[lastElement.fd] = entry;
|
||||
|
||||
// Now move it properly (lastElement is invalid after the following line) and pop it
|
||||
m_sockets[entry] = std::move(m_sockets.back());
|
||||
}
|
||||
|
||||
m_sockets.pop_back();
|
||||
m_activeSockets.erase(socket);
|
||||
m_allSockets.erase(socket);
|
||||
}
|
||||
|
||||
int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
|
||||
{
|
||||
int activeSockets;
|
||||
|
||||
// Reset status of sockets
|
||||
for (PollSocket& entry : m_sockets)
|
||||
entry.revents = 0;
|
||||
|
||||
activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
|
||||
|
||||
m_activeSockets.clear();
|
||||
if (activeSockets > 0U)
|
||||
{
|
||||
int socketRemaining = activeSockets;
|
||||
for (PollSocket& entry : m_sockets)
|
||||
{
|
||||
if (entry.revents & POLLRDNORM)
|
||||
{
|
||||
m_activeSockets.insert(entry.fd);
|
||||
if (--socketRemaining == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return activeSockets;
|
||||
}
|
||||
}
|
||||
42
src/Nazara/Network/Posix/SocketPollerImpl.hpp
Normal file
42
src/Nazara/Network/Posix/SocketPollerImpl.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
#define NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
#include <Nazara/Network/SocketHandle.hpp>
|
||||
#include <Nazara/Network/Posix/SocketImpl.hpp>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class SocketPollerImpl
|
||||
{
|
||||
public:
|
||||
SocketPollerImpl() = default;
|
||||
~SocketPollerImpl() = default;
|
||||
|
||||
void Clear();
|
||||
|
||||
bool IsReady(SocketHandle socket) const;
|
||||
bool IsRegistered(SocketHandle socket) const;
|
||||
|
||||
bool RegisterSocket(SocketHandle socket);
|
||||
void UnregisterSocket(SocketHandle socket);
|
||||
|
||||
int Wait(UInt64 msTimeout, SocketError* error);
|
||||
|
||||
private:
|
||||
std::unordered_set<SocketHandle> m_activeSockets;
|
||||
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
|
||||
std::vector<PollSocket> m_sockets;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
170
src/Nazara/Network/SocketPoller.cpp
Normal file
170
src/Nazara/Network/SocketPoller.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Network/SocketPoller.hpp>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Network/Win32/SocketPollerImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
#include <Nazara/Network/Linux/SocketPollerImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <Nazara/Network/Posix/SocketPollerImpl.hpp>
|
||||
#else
|
||||
#error Missing implementation: SocketPoller
|
||||
#endif
|
||||
|
||||
#include <Nazara/Network/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup network
|
||||
* \class Nz::SocketPoller
|
||||
* \brief Network class allowing an application to wait on multiples sockets for them to become active (readable)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an empty SocketPoller object
|
||||
*/
|
||||
SocketPoller::SocketPoller() :
|
||||
m_impl(new SocketPollerImpl)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the SocketPoller
|
||||
*
|
||||
* \remark When the SocketPoller gets destroyed, all sockets are automatically unregistered from it.
|
||||
*/
|
||||
SocketPoller::~SocketPoller()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clears the SocketPoller
|
||||
*
|
||||
* This function reverts the SocketPoller to the initial state, unregistering every socket from the SocketPoller.
|
||||
*
|
||||
* \see Unregister
|
||||
*/
|
||||
void SocketPoller::Clear()
|
||||
{
|
||||
m_impl->Clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks if a specific socket is ready to read data
|
||||
*
|
||||
* This function allows you to read the results of the last Wait operation and if a specific socket is ready.
|
||||
*
|
||||
* A socket in the ready state (with the exception of TcpServer) has incoming data and can be read without blocking.
|
||||
*
|
||||
* \remark When used on a TcpServer socket, this function returns true if the server is ready to accept a new client.
|
||||
* \remark You must call Wait before using this function in order to refresh the state.
|
||||
*
|
||||
* \param socket Reference to the socket to check
|
||||
*
|
||||
* \return True if the socket is available for reading without blocking, false otherwise
|
||||
*
|
||||
* \see Wait
|
||||
*/
|
||||
bool SocketPoller::IsReady(const AbstractSocket& socket) const
|
||||
{
|
||||
NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller");
|
||||
|
||||
return m_impl->IsReady(socket.GetNativeHandle());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks if a specific socket is registered in the SocketPoller
|
||||
*
|
||||
* A registered socket is part of the SocketPoller and will be checked by the next Wait operations.
|
||||
*
|
||||
* \param socket Reference to the socket to check
|
||||
*
|
||||
* \return True if the socket is registered, false otherwise
|
||||
*
|
||||
* \see RegisterSocket
|
||||
* \see UnregisterSocket
|
||||
*/
|
||||
bool SocketPoller::IsRegistered(const AbstractSocket& socket) const
|
||||
{
|
||||
return m_impl->IsRegistered(socket.GetNativeHandle());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Register a socket in the SocketPoller
|
||||
*
|
||||
* A registered socket is part of the SocketPoller and will be checked by the next Wait operations.
|
||||
*
|
||||
* The SocketPoller keeps a reference to the internal handle of registered socket, which should not be freed while it is registered in the SocketPooler.
|
||||
*
|
||||
* It is possible for this function to fail if too many sockets are registered in the SocketPoller, the maximum number of socket handled limit is OS-dependent.
|
||||
*
|
||||
* \remark It is an error to register a socket twice in the same SocketPoller.
|
||||
* \remark The socket should not be freed while it is registered in the SocketPooler.
|
||||
*
|
||||
* \param socket Reference to the socket to register
|
||||
*
|
||||
* \return True if the socket is registered, false otherwise
|
||||
*
|
||||
* \see IsRegistered
|
||||
* \see UnregisterSocket
|
||||
*/
|
||||
bool SocketPoller::RegisterSocket(AbstractSocket& socket)
|
||||
{
|
||||
NazaraAssert(!IsRegistered(socket), "This socket is already registered in this SocketPoller");
|
||||
|
||||
return m_impl->RegisterSocket(socket.GetNativeHandle());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Unregister a socket from the SocketPoller
|
||||
*
|
||||
* After calling UnregisterSocket, the socket is no longer part of the SocketPoller and thus, not taken into account by any further Wait call until registered again.
|
||||
*
|
||||
* This function must be called before destroying a socket part of the SocketPoller.
|
||||
*
|
||||
* \remark It is an error to try to unregister a non-registered socket from a SocketPoller.
|
||||
*
|
||||
* \param socket Reference to the socket to unregister
|
||||
*
|
||||
* \see IsRegistered
|
||||
* \see RegisterSocket
|
||||
*/
|
||||
void SocketPoller::UnregisterSocket(AbstractSocket& socket)
|
||||
{
|
||||
NazaraAssert(IsRegistered(socket), "This socket is not registered in this SocketPoller");
|
||||
|
||||
return m_impl->UnregisterSocket(socket.GetNativeHandle());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Wait until any registered socket switches to a ready state
|
||||
*
|
||||
* Waits a specific/undetermined amount of time until at least one socket part of the SocketPoller becomes ready.
|
||||
* To query the ready state of the registered socket, use the IsReady function.
|
||||
*
|
||||
* \param msTimeout Maximum time to wait in milliseconds, 0 for infinity
|
||||
*
|
||||
* \remark It is an error to try to unregister a non-registered socket from a SocketPoller.
|
||||
*
|
||||
* \see IsReady
|
||||
* \see RegisterSocket
|
||||
*/
|
||||
bool SocketPoller::Wait(UInt64 msTimeout)
|
||||
{
|
||||
SocketError error;
|
||||
|
||||
int readySockets = m_impl->Wait(msTimeout, &error);
|
||||
if (error != SocketError_NoError)
|
||||
{
|
||||
NazaraError("SocketPoller encountered an error (code: 0x" + String::Number(error, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
return readySockets > 0;
|
||||
}
|
||||
}
|
||||
@@ -262,6 +262,17 @@ namespace Nz
|
||||
if (m_pendingPacket.headerReceived)
|
||||
{
|
||||
UInt16 packetSize = static_cast<UInt16>(m_pendingPacket.data.GetSize()); //< Total packet size
|
||||
if (packetSize == 0)
|
||||
{
|
||||
// Special case: our packet carry no data
|
||||
packet->Reset(m_pendingPacket.netcode);
|
||||
|
||||
// And reset every state
|
||||
m_pendingPacket.data.Clear();
|
||||
m_pendingPacket.headerReceived = false;
|
||||
m_pendingPacket.received = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t received;
|
||||
if (!Receive(&m_pendingPacket.data[m_pendingPacket.received], packetSize - m_pendingPacket.received, &received))
|
||||
|
||||
@@ -13,12 +13,12 @@ namespace Nz
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
using addrinfoImpl = addrinfoW;
|
||||
|
||||
int GetAddressInfo(const String& hostname, const String& service, const addrinfoImpl* hints, addrinfoImpl** results)
|
||||
{
|
||||
return GetAddrInfoW(hostname.GetWideString().c_str(), service.GetWideString().c_str(), &hints, &servinfo);
|
||||
return GetAddrInfoW(hostname.GetWideString().c_str(), service.GetWideString().c_str(), hints, results);
|
||||
}
|
||||
|
||||
int GetHostnameInfo(sockaddr* socketAddress, socklen_t socketLen, String* hostname, String* service, INT flags)
|
||||
@@ -26,14 +26,14 @@ namespace Nz
|
||||
std::array<wchar_t, NI_MAXHOST> hostnameBuffer;
|
||||
std::array<wchar_t, NI_MAXSERV> serviceBuffer;
|
||||
|
||||
int result = GetNameInfoW(socketAddress, socketLen, hostnameBuffer.data(), hostnameBuffer.size(), serviceBuffer.data(), serviceBuffer.size(), flags);
|
||||
int result = GetNameInfoW(socketAddress, socketLen, hostnameBuffer.data(), static_cast<DWORD>(hostnameBuffer.size()), serviceBuffer.data(), static_cast<DWORD>(serviceBuffer.size()), flags);
|
||||
if (result == 0)
|
||||
{
|
||||
if (hostname)
|
||||
hostname->Set(hostnameBuffer.data());
|
||||
*hostname = std::move(String::Unicode(hostnameBuffer.data()));
|
||||
|
||||
if (service)
|
||||
service->Set(serviceBuffer.data());
|
||||
*service = std::move(String::Unicode(serviceBuffer.data()));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -105,7 +105,7 @@ namespace Nz
|
||||
return IpAddress::Invalid;
|
||||
}
|
||||
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
IpAddress IpAddressImpl::FromAddrinfo(const addrinfoW* info)
|
||||
{
|
||||
switch (info->ai_family)
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_IPADDRESSIMPL_HPP
|
||||
#define NAZARA_IPADDRESSIMPL_HPP
|
||||
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
@@ -17,7 +22,7 @@ namespace Nz
|
||||
~IpAddressImpl() = delete;
|
||||
|
||||
static IpAddress FromAddrinfo(const addrinfo* info);
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
#if NAZARA_CORE_WINDOWS_NT6
|
||||
static IpAddress FromAddrinfo(const addrinfoW* info);
|
||||
#endif
|
||||
static IpAddress FromSockAddr(const sockaddr* address);
|
||||
@@ -33,3 +38,5 @@ namespace Nz
|
||||
static ResolveError TranslateWSAErrorToResolveError(int error);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_IPADDRESSIMPL_HPP
|
||||
@@ -7,18 +7,21 @@
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Network/Win32/IpAddressImpl.hpp>
|
||||
|
||||
#include <Winsock2.h>
|
||||
|
||||
#if defined(NAZARA_COMPILER_MINGW) && __GNUC__ < 5
|
||||
// Some compilers (olders versions of MinGW) are lacking Mstcpip.h which defines the following struct/#define
|
||||
// Define them ourself for now
|
||||
struct tcp_keepalive
|
||||
{
|
||||
u_long onoff;
|
||||
u_long keepalivetime;
|
||||
u_long keepaliveinterval;
|
||||
u_long onoff;
|
||||
u_long keepalivetime;
|
||||
u_long keepaliveinterval;
|
||||
};
|
||||
|
||||
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
|
||||
#else
|
||||
#include <Mstcpip.h>
|
||||
#endif
|
||||
|
||||
#include <Winsock2.h>
|
||||
|
||||
#include <Nazara/Network/Debug.hpp>
|
||||
|
||||
@@ -412,6 +415,34 @@ namespace Nz
|
||||
return IpAddressImpl::FromSockAddr(reinterpret_cast<sockaddr*>(nameBuffer.data()));
|
||||
}
|
||||
|
||||
int SocketImpl::Poll(PollSocket* fdarray, std::size_t nfds, int timeout, SocketError* error)
|
||||
{
|
||||
NazaraAssert(fdarray && nfds > 0, "Invalid fdarray");
|
||||
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
static_assert(sizeof(PollSocket) == sizeof(WSAPOLLFD), "PollSocket size must match WSAPOLLFD size");
|
||||
|
||||
int result = WSAPoll(reinterpret_cast<WSAPOLLFD*>(fdarray), static_cast<ULONG>(nfds), timeout);
|
||||
if (result == SOCKET_ERROR)
|
||||
{
|
||||
int errorCode = WSAGetLastError();
|
||||
if (error)
|
||||
*error = TranslateWSAErrorToSocketError(errorCode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
|
||||
return result;
|
||||
#else
|
||||
if (error)
|
||||
*error = SocketError_NotSupported;
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketImpl::Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error)
|
||||
{
|
||||
|
||||
@@ -2,13 +2,27 @@
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SOCKETIMPL_HPP
|
||||
#define NAZARA_SOCKETIMPL_HPP
|
||||
|
||||
#include <Nazara/Network/SocketHandle.hpp>
|
||||
#include <Nazara/Network/Enums.hpp>
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
#include <winsock2.h>
|
||||
|
||||
#define NAZARA_NETWORK_POLL_SUPPORT NAZARA_CORE_WINDOWS_NT6
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
struct PollSocket
|
||||
{
|
||||
SocketHandle fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
|
||||
class SocketImpl
|
||||
{
|
||||
public:
|
||||
@@ -43,6 +57,8 @@ namespace Nz
|
||||
static IpAddress QueryPeerAddress(SocketHandle handle, SocketError* error = nullptr);
|
||||
static IpAddress QuerySocketAddress(SocketHandle handle, SocketError* error = nullptr);
|
||||
|
||||
static int Poll(PollSocket* fdarray, std::size_t nfds, int timeout, SocketError* error);
|
||||
|
||||
static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error);
|
||||
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);
|
||||
|
||||
@@ -66,3 +82,5 @@ namespace Nz
|
||||
static WSADATA s_WSA;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_SOCKETIMPL_HPP
|
||||
149
src/Nazara/Network/Win32/SocketPollerImpl.cpp
Normal file
149
src/Nazara/Network/Win32/SocketPollerImpl.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Network/Win32/SocketPollerImpl.hpp>
|
||||
#include <Nazara/Network/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
SocketPollerImpl::SocketPollerImpl()
|
||||
{
|
||||
#if !NAZARA_NETWORK_POLL_SUPPORT
|
||||
FD_ZERO(&m_activeSockets);
|
||||
FD_ZERO(&m_sockets);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SocketPollerImpl::Clear()
|
||||
{
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
m_activeSockets.clear();
|
||||
m_allSockets.clear();
|
||||
m_sockets.clear();
|
||||
#else
|
||||
FD_ZERO(&m_activeSockets);
|
||||
FD_ZERO(&m_sockets);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::IsReady(SocketHandle socket) const
|
||||
{
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
return m_activeSockets.count(socket) != 0;
|
||||
#else
|
||||
return FD_ISSET(socket, &m_activeSockets) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
|
||||
{
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
return m_allSockets.count(socket) != 0;
|
||||
#else
|
||||
return FD_ISSET(socket, &m_sockets) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
|
||||
{
|
||||
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
||||
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
PollSocket entry = {
|
||||
socket,
|
||||
POLLRDNORM,
|
||||
0
|
||||
};
|
||||
|
||||
m_allSockets[socket] = m_sockets.size();
|
||||
m_sockets.emplace_back(entry);
|
||||
#else
|
||||
if (m_sockets.fd_count > FD_SETSIZE)
|
||||
{
|
||||
NazaraError("Socket count exceeding FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
FD_SET(socket, &m_sockets);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SocketPollerImpl::UnregisterSocket(SocketHandle socket)
|
||||
{
|
||||
NazaraAssert(IsRegistered(socket), "Socket is not registered");
|
||||
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
if (m_sockets.size() > 1U)
|
||||
{
|
||||
// Instead of using vector::erase, let's move the last element to the now unoccupied position
|
||||
std::size_t entry = m_allSockets[socket];
|
||||
|
||||
// Get the last element and update it's position
|
||||
const PollSocket& lastElement = m_sockets.back();
|
||||
m_allSockets[lastElement.fd] = entry;
|
||||
|
||||
// Now move it properly (lastElement is invalid after the following line) and pop it
|
||||
m_sockets[entry] = std::move(m_sockets.back());
|
||||
}
|
||||
|
||||
m_sockets.pop_back();
|
||||
m_activeSockets.erase(socket);
|
||||
m_allSockets.erase(socket);
|
||||
#else
|
||||
FD_CLR(socket, &m_activeSockets);
|
||||
FD_CLR(socket, &m_sockets);
|
||||
#endif
|
||||
}
|
||||
|
||||
int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
|
||||
{
|
||||
int activeSockets;
|
||||
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
// Reset status of sockets
|
||||
for (PollSocket& entry : m_sockets)
|
||||
entry.revents = 0;
|
||||
|
||||
activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
|
||||
|
||||
m_activeSockets.clear();
|
||||
if (activeSockets > 0U)
|
||||
{
|
||||
int socketRemaining = activeSockets;
|
||||
for (PollSocket& entry : m_sockets)
|
||||
{
|
||||
if (entry.revents & POLLRDNORM)
|
||||
{
|
||||
m_activeSockets.insert(entry.fd);
|
||||
if (--socketRemaining == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
m_activeSockets = m_sockets;
|
||||
|
||||
timeval tv;
|
||||
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
|
||||
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
|
||||
|
||||
activeSockets = ::select(0xDEADBEEF, &m_activeSockets, nullptr, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
|
||||
if (activeSockets == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
*error = SocketImpl::TranslateWSAErrorToSocketError(WSAGetLastError());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = SocketError_NoError;
|
||||
#endif
|
||||
|
||||
return activeSockets;
|
||||
}
|
||||
}
|
||||
48
src/Nazara/Network/Win32/SocketPollerImpl.hpp
Normal file
48
src/Nazara/Network/Win32/SocketPollerImpl.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Network module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
#define NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
|
||||
#include <Nazara/Network/IpAddress.hpp>
|
||||
#include <Nazara/Network/SocketHandle.hpp>
|
||||
#include <Nazara/Network/Win32/SocketImpl.hpp>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <winsock2.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class SocketPollerImpl
|
||||
{
|
||||
public:
|
||||
SocketPollerImpl();
|
||||
~SocketPollerImpl() = default;
|
||||
|
||||
void Clear();
|
||||
|
||||
bool IsReady(SocketHandle socket) const;
|
||||
bool IsRegistered(SocketHandle socket) const;
|
||||
|
||||
bool RegisterSocket(SocketHandle socket);
|
||||
void UnregisterSocket(SocketHandle socket);
|
||||
|
||||
int Wait(UInt64 msTimeout, SocketError* error);
|
||||
|
||||
private:
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
std::unordered_set<SocketHandle> m_activeSockets;
|
||||
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
|
||||
std::vector<PollSocket> m_sockets;
|
||||
#else
|
||||
fd_set m_sockets;
|
||||
fd_set m_activeSockets;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_SOCKETPOLLERIMPL_HPP
|
||||
@@ -76,7 +76,7 @@ namespace Nz
|
||||
|
||||
code << "#define GLSL_VERSION " << glslVersion << "\n\n";
|
||||
|
||||
code << "#define EARLY_FRAGMENT_TEST " << (glslVersion >= 420 || OpenGL::IsSupported(OpenGLExtension_Shader_ImageLoadStore)) << "\n\n";
|
||||
code << "#define EARLY_FRAGMENT_TEST " << ((glslVersion >= 420 || OpenGL::IsSupported(OpenGLExtension_Shader_ImageLoadStore)) ? '1' : '0') << "\n\n";
|
||||
|
||||
for (auto it = shaderStage.flags.begin(); it != shaderStage.flags.end(); ++it)
|
||||
code << "#define " << it->first << ' ' << ((stageFlags & it->second) ? '1' : '0') << '\n';
|
||||
|
||||
@@ -37,6 +37,10 @@ namespace Nz
|
||||
if (parameters.custom.GetBooleanParameter("SkipNativeOBJLoader", &skip) && skip)
|
||||
return Ternary_False;
|
||||
|
||||
OBJParser parser;
|
||||
if (!parser.Check(stream))
|
||||
return Ternary_False;
|
||||
|
||||
return Ternary_Unknown;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,87 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool OBJParser::Check(Stream& stream)
|
||||
{
|
||||
m_currentStream = &stream;
|
||||
m_errorCount = 0;
|
||||
m_keepLastLine = false;
|
||||
m_lineCount = 0;
|
||||
|
||||
// Force stream in text mode, reset it at the end
|
||||
Nz::CallOnExit resetTextMode;
|
||||
if ((stream.GetStreamOptions() & StreamOption_Text) == 0)
|
||||
{
|
||||
stream.EnableTextMode(true);
|
||||
|
||||
resetTextMode.Reset([&stream] ()
|
||||
{
|
||||
stream.EnableTextMode(false);
|
||||
});
|
||||
}
|
||||
|
||||
unsigned int failureCount = 0;
|
||||
while (Advance(false))
|
||||
{
|
||||
switch (std::tolower(m_currentLine[0]))
|
||||
{
|
||||
case '#': //< Comment
|
||||
failureCount--;
|
||||
break;
|
||||
|
||||
case 'f': //< Face
|
||||
case 'g': //< Group (inside a mesh)
|
||||
case 'o': //< Object (defines a mesh)
|
||||
case 's': //< Smooth
|
||||
{
|
||||
if (m_currentLine.GetSize() > 1 && m_currentLine[1] == ' ')
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'm': //< MTLLib
|
||||
if (m_currentLine.GetWord(0).ToLower() == "mtllib")
|
||||
return true;
|
||||
|
||||
break;
|
||||
|
||||
case 'u': //< Usemtl
|
||||
if (m_currentLine.GetWord(0).ToLower() == "usemtl")
|
||||
return true;
|
||||
|
||||
break;
|
||||
|
||||
case 'v': //< Position/Normal/Texcoords
|
||||
{
|
||||
String word = m_currentLine.GetWord(0).ToLower();
|
||||
if (word == 'v')
|
||||
return true;
|
||||
else if (word == "vn")
|
||||
return true;
|
||||
else if (word == "vt")
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (++failureCount > 20U)
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OBJParser::Parse(Nz::Stream& stream, UInt32 reservedVertexCount)
|
||||
{
|
||||
m_currentStream = &stream;
|
||||
m_errorCount = 0;
|
||||
m_keepLastLine = false;
|
||||
m_lineCount = 0;
|
||||
|
||||
// Force stream in text mode, reset it at the end
|
||||
Nz::CallOnExit resetTextMode;
|
||||
@@ -31,9 +109,6 @@ namespace Nz
|
||||
|
||||
String matName, meshName;
|
||||
matName = meshName = "default";
|
||||
m_errorCount = 0;
|
||||
m_keepLastLine = false;
|
||||
m_lineCount = 0;
|
||||
m_meshes.clear();
|
||||
m_mtlLib.Clear();
|
||||
|
||||
|
||||
@@ -1284,6 +1284,9 @@ namespace Nz
|
||||
|
||||
bool PixelFormat::Initialize()
|
||||
{
|
||||
Bitset<> b32(0xFFFFFFFF);
|
||||
b32.Resize(128);
|
||||
|
||||
// Setup informations about every pixel format
|
||||
s_pixelFormatInfos[PixelFormatType_A8] = PixelFormatInfo("A8", PixelFormatContent_ColorRGBA, 0, 0, 0, 0xFF, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_BGR8] = PixelFormatInfo("BGR8", PixelFormatContent_ColorRGBA, 0x0000FF, 0x00FF00, 0xFF0000, 0, PixelFormatSubType_Unsigned);
|
||||
@@ -1317,18 +1320,18 @@ namespace Nz
|
||||
s_pixelFormatInfos[PixelFormatType_RGB16F] = PixelFormatInfo("RGB16F", PixelFormatContent_ColorRGBA, 0xFFFF00000000, 0x0000FFFF0000, 0x00000000FFFF, 0, PixelFormatSubType_Half);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB16I] = PixelFormatInfo("RGB16I", PixelFormatContent_ColorRGBA, 0xFFFF00000000, 0x0000FFFF0000, 0x00000000FFFF, 0, PixelFormatSubType_Int);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB16UI] = PixelFormatInfo("RGB16UI", PixelFormatContent_ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB32F] = PixelFormatInfo("RGB32F", PixelFormatContent_ColorRGBA, 0, 0, 0, 0, PixelFormatSubType_Half);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB32I] = PixelFormatInfo("RGB32I", PixelFormatContent_ColorRGBA, 0, 0, 0, 0, PixelFormatSubType_Int);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB32UI] = PixelFormatInfo("RGB32UI", PixelFormatContent_ColorRGBA, 0, 0, 0, 0, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB32F] = PixelFormatInfo("RGB32F", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType_Float);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB32I] = PixelFormatInfo("RGB32I", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType_Int);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB32UI] = PixelFormatInfo("RGB32UI", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, 0, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA4] = PixelFormatInfo("RGBA4", PixelFormatContent_ColorRGBA, 0xF000, 0x0F00, 0x00F0, 0x000F, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_RGB5A1] = PixelFormatInfo("RGB5A1", PixelFormatContent_ColorRGBA, 0xF800, 0x07C0, 0x003E, 0x0001, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA8] = PixelFormatInfo("RGBA8", PixelFormatContent_ColorRGBA, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA16F] = PixelFormatInfo("RGBA16F", PixelFormatContent_ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType_Half);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA16I] = PixelFormatInfo("RGBA16I", PixelFormatContent_ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType_Int);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA16UI] = PixelFormatInfo("RGBA16UI", PixelFormatContent_ColorRGBA, 0xFFFF000000000000, 0x0000FFFF00000000, 0x00000000FFFF0000, 0x000000000000FFFF, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA32F] = PixelFormatInfo("RGBA32F", PixelFormatContent_ColorRGBA, 0, 0, 0, 0, PixelFormatSubType_Half);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA32I] = PixelFormatInfo("RGBA32I", PixelFormatContent_ColorRGBA, 0, 0, 0, 0, PixelFormatSubType_Int);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA32UI] = PixelFormatInfo("RGBA32UI", PixelFormatContent_ColorRGBA, 0, 0, 0, 0, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA32F] = PixelFormatInfo("RGBA32F", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType_Float);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA32I] = PixelFormatInfo("RGBA32I", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType_Int);
|
||||
s_pixelFormatInfos[PixelFormatType_RGBA32UI] = PixelFormatInfo("RGBA32UI", PixelFormatContent_ColorRGBA, b32, b32 >> 32, b32 >> 64, b32 >> 96, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_Depth16] = PixelFormatInfo("Depth16", PixelFormatContent_DepthStencil, 0xFFFF, 0, 0, 0, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_Depth24] = PixelFormatInfo("Depth24", PixelFormatContent_DepthStencil, 0xFFFFFF, 0, 0, 0, PixelFormatSubType_Unsigned);
|
||||
s_pixelFormatInfos[PixelFormatType_Depth24Stencil8] = PixelFormatInfo("Depth24Stencil8", PixelFormatContent_DepthStencil, 0xFFFFFF00, 0x000000FF, 0, 0, PixelFormatSubType_Unsigned);
|
||||
|
||||
@@ -102,10 +102,14 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Window::Initialize())
|
||||
bool bParam;
|
||||
if (!s_initializationParameters.GetBooleanParameter("NoWindowSystem", &bParam) || !bParam)
|
||||
{
|
||||
NazaraError("Failed to initialize window's system");
|
||||
return false;
|
||||
if (!Window::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize window's system");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// On enregistre les loaders pour les extensions
|
||||
@@ -147,6 +151,11 @@ namespace Nz
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
void Utility::SetParameters(const ParameterList& parameters)
|
||||
{
|
||||
s_initializationParameters = parameters;
|
||||
}
|
||||
|
||||
void Utility::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
@@ -227,5 +236,6 @@ namespace Nz
|
||||
|
||||
static_assert(ComponentType_Max+1 == 14, "Component stride array is incomplete");
|
||||
|
||||
ParameterList Utility::s_initializationParameters;
|
||||
unsigned int Utility::s_moduleReferenceCounter = 0;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ namespace Nz
|
||||
Window* fullscreenWindow = nullptr;
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool Window::Create(VideoMode mode, const String& title, UInt32 style)
|
||||
{
|
||||
// Si la fenêtre est déjà ouverte, nous conservons sa position
|
||||
|
||||
@@ -9,7 +9,17 @@
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/Utility/X11/Display.hpp>
|
||||
#include <xcb/xcb_image.h>
|
||||
#include <xcb/xcb_renderutil.h>
|
||||
|
||||
// Some older versions of xcb/util-renderutil (notably the one available on Travis CI) use `template` as an argument name
|
||||
// This is a fixed bug (https://cgit.freedesktop.org/xcb/util-renderutil/commit/?id=8d15acc45a47dc4c922eee5b99885db42bc62c17) but until Travis-CI
|
||||
// has upgraded their Ubuntu version, I'm forced to use this ugly trick.
|
||||
#define template ptemplate
|
||||
extern "C"
|
||||
{
|
||||
#include <xcb/xcb_renderutil.h>
|
||||
}
|
||||
#undef template
|
||||
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
|
||||
Reference in New Issue
Block a user