Merge remote-tracking branch 'refs/remotes/origin/master' into reflection-mapping

This commit is contained in:
Lynix
2017-06-10 22:33:03 +02:00
93 changed files with 7350 additions and 2961 deletions

View File

@@ -95,7 +95,7 @@ namespace Nz
}
case ParameterType_Color:
case ParameterType_Float:
case ParameterType_Double:
case ParameterType_None:
case ParameterType_Pointer:
case ParameterType_Userdata:
@@ -137,9 +137,9 @@ namespace Nz
return true;
case ParameterType_Boolean:
case ParameterType_Double:
case ParameterType_Integer:
case ParameterType_String:
case ParameterType_Float:
case ParameterType_None:
case ParameterType_Pointer:
case ParameterType_Userdata:
@@ -151,19 +151,19 @@ namespace Nz
}
/*!
* \brief Gets a parameter as a float
* \return true if the parameter could be represented as a float
* \brief Gets a parameter as a double
* \return true if the parameter could be represented as a double
*
* \param name Name of the parameter
* \param value Pointer to a float to hold the retrieved value
* \param value Pointer to a double to hold the retrieved value
*
* \remark value must be a valid pointer
* \remark In case of failure, the variable pointed by value keep its value
* \remark If the parameter is not a float, a conversion will be performed, compatibles types are:
Integer: The integer value is converted to its float representation
* \remark If the parameter is not a double, a conversion will be performed, compatibles types are:
Integer: The integer value is converted to its double representation
String: Conversion obeys the rule as described by String::ToDouble
*/
bool ParameterList::GetFloatParameter(const String& name, float* value) const
bool ParameterList::GetDoubleParameter(const String& name, double* value) const
{
NazaraAssert(value, "Invalid pointer");
@@ -178,12 +178,12 @@ namespace Nz
switch (it->second.type)
{
case ParameterType_Float:
*value = it->second.value.floatVal;
case ParameterType_Double:
*value = it->second.value.doubleVal;
return true;
case ParameterType_Integer:
*value = static_cast<float>(it->second.value.intVal);
*value = static_cast<double>(it->second.value.intVal);
return true;
case ParameterType_String:
@@ -191,7 +191,7 @@ namespace Nz
double converted;
if (it->second.value.stringVal.ToDouble(&converted))
{
*value = static_cast<float>(converted);
*value = converted;
return true;
}
@@ -206,7 +206,7 @@ namespace Nz
break;
}
NazaraError("Parameter value is not representable as a float");
NazaraError("Parameter value is not representable as a double");
return false;
}
@@ -219,12 +219,12 @@ namespace Nz
*
* \remark value must be a valid pointer
* \remark In case of failure, the variable pointed by value keep its value
* \remark If the parameter is not a float, a conversion will be performed, compatibles types are:
* \remark If the parameter is not an integer, a conversion will be performed, compatibles types are:
Boolean: The boolean is represented as 1 if true and 0 if false
Float: The floating-point value is truncated and converted to a integer
String: Conversion obeys the rule as described by String::ToInteger but fails if the value could not be represented as a int
Double: The floating-point value is truncated and converted to a integer
String: Conversion obeys the rule as described by String::ToInteger
*/
bool ParameterList::GetIntegerParameter(const String& name, int* value) const
bool ParameterList::GetIntegerParameter(const String& name, long long* value) const
{
NazaraAssert(value, "Invalid pointer");
@@ -243,8 +243,8 @@ namespace Nz
*value = (it->second.value.boolVal) ? 1 : 0;
return true;
case ParameterType_Float:
*value = static_cast<int>(it->second.value.floatVal);
case ParameterType_Double:
*value = static_cast<long long>(it->second.value.doubleVal);
return true;
case ParameterType_Integer:
@@ -256,11 +256,8 @@ namespace Nz
long long converted;
if (it->second.value.stringVal.ToInteger(&converted))
{
if (converted <= std::numeric_limits<int>::max() && converted >= std::numeric_limits<int>::min())
{
*value = static_cast<int>(converted);
return true;
}
*value = converted;
return true;
}
break;
}
@@ -335,7 +332,7 @@ namespace Nz
case ParameterType_Boolean:
case ParameterType_Color:
case ParameterType_Float:
case ParameterType_Double:
case ParameterType_Integer:
case ParameterType_None:
case ParameterType_String:
@@ -358,7 +355,7 @@ namespace Nz
* \remark If the parameter is not a string, a conversion will be performed, all types are compatibles:
Boolean: Conversion obeys the rules of String::Boolean
Color: Conversion obeys the rules of Color::ToString
Float: Conversion obeys the rules of String::Number
Double: Conversion obeys the rules of String::Number
Integer: Conversion obeys the rules of String::Number
None: An empty string is returned
Pointer: Conversion obeys the rules of String::Pointer
@@ -387,8 +384,8 @@ namespace Nz
*value = it->second.value.colorVal.ToString();
return true;
case ParameterType_Float:
*value = String::Number(it->second.value.floatVal);
case ParameterType_Double:
*value = String::Number(it->second.value.doubleVal);
return true;
case ParameterType_Integer:
@@ -560,18 +557,18 @@ namespace Nz
}
/*!
* \brief Sets a float parameter named `name`
* \brief Sets a double parameter named `name`
*
* If a parameter already exists with that name, it is destroyed and replaced by this call
*
* \param name Name of the parameter
* \param value The float value
* \param value The double value
*/
void ParameterList::SetParameter(const String& name, float value)
void ParameterList::SetParameter(const String& name, double value)
{
Parameter& parameter = CreateValue(name);
parameter.type = ParameterType_Float;
parameter.value.floatVal = value;
parameter.type = ParameterType_Double;
parameter.value.doubleVal = value;
}
/*!
@@ -582,7 +579,7 @@ namespace Nz
* \param name Name of the parameter
* \param value The integer value
*/
void ParameterList::SetParameter(const String& name, int value)
void ParameterList::SetParameter(const String& name, long long value)
{
Parameter& parameter = CreateValue(name);
parameter.type = ParameterType_Integer;
@@ -627,8 +624,8 @@ namespace Nz
case ParameterType_Color:
ss << "Color(" << it->second.value.colorVal.ToString() << ")";
break;
case ParameterType_Float:
ss << "Float(" << it->second.value.floatVal << ")";
case ParameterType_Double:
ss << "Double(" << it->second.value.doubleVal << ")";
break;
case ParameterType_Integer:
ss << "Integer(" << it->second.value.intVal << ")";
@@ -692,7 +689,7 @@ namespace Nz
{
case ParameterType_Boolean:
case ParameterType_Color:
case ParameterType_Float:
case ParameterType_Double:
case ParameterType_Integer:
case ParameterType_Pointer:
std::memcpy(&parameter, &it->second, sizeof(Parameter));
@@ -764,7 +761,7 @@ namespace Nz
case ParameterType_Boolean:
case ParameterType_Color:
case ParameterType_Float:
case ParameterType_Double:
case ParameterType_Integer:
case ParameterType_None:
case ParameterType_Pointer:

View File

@@ -114,14 +114,14 @@ namespace Nz
{
Color color;
bool isEnabled;
float fValue;
int iValue;
double dValue;
long long iValue;
String path;
ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled, true);
if (matData.GetFloatParameter(MaterialData::AlphaThreshold, &fValue))
SetAlphaThreshold(fValue);
if (matData.GetDoubleParameter(MaterialData::AlphaThreshold, &dValue))
SetAlphaThreshold(float(dValue));
if (matData.GetBooleanParameter(MaterialData::AlphaTest, &isEnabled))
EnableAlphaTest(isEnabled);
@@ -147,17 +147,17 @@ namespace Nz
if (matData.GetIntegerParameter(MaterialData::FaceFilling, &iValue))
SetFaceFilling(static_cast<FaceFilling>(iValue));
if (matData.GetFloatParameter(MaterialData::LineWidth, &fValue))
SetLineWidth(fValue);
if (matData.GetDoubleParameter(MaterialData::LineWidth, &dValue))
SetLineWidth(float(dValue));
if (matData.GetFloatParameter(MaterialData::PointSize, &fValue))
SetPointSize(fValue);
if (matData.GetDoubleParameter(MaterialData::PointSize, &dValue))
SetPointSize(float(dValue));
if (matData.GetColorParameter(MaterialData::SpecularColor, &color))
SetSpecularColor(color);
if (matData.GetFloatParameter(MaterialData::Shininess, &fValue))
SetShininess(fValue);
if (matData.GetDoubleParameter(MaterialData::Shininess, &dValue))
SetShininess(float(dValue));
if (matData.GetIntegerParameter(MaterialData::SrcBlend, &iValue))
SetSrcBlend(static_cast<BlendFunc>(iValue));
@@ -277,17 +277,17 @@ namespace Nz
matData->SetParameter(MaterialData::AlphaTest, IsAlphaTestEnabled());
matData->SetParameter(MaterialData::AlphaThreshold, GetAlphaThreshold());
matData->SetParameter(MaterialData::AmbientColor, GetAmbientColor());
matData->SetParameter(MaterialData::CullingSide, int(GetFaceCulling()));
matData->SetParameter(MaterialData::DepthFunc, int(GetDepthFunc()));
matData->SetParameter(MaterialData::CullingSide, static_cast<long long>(GetFaceCulling()));
matData->SetParameter(MaterialData::DepthFunc, static_cast<long long>(GetDepthFunc()));
matData->SetParameter(MaterialData::DepthSorting, IsDepthSortingEnabled());
matData->SetParameter(MaterialData::DiffuseColor, GetDiffuseColor());
matData->SetParameter(MaterialData::DstBlend, int(GetDstBlend()));
matData->SetParameter(MaterialData::FaceFilling, int(GetFaceFilling()));
matData->SetParameter(MaterialData::DstBlend, static_cast<long long>(GetDstBlend()));
matData->SetParameter(MaterialData::FaceFilling, static_cast<long long>(GetFaceFilling()));
matData->SetParameter(MaterialData::LineWidth, GetLineWidth());
matData->SetParameter(MaterialData::PointSize, GetPointSize());
matData->SetParameter(MaterialData::Shininess, GetShininess());
matData->SetParameter(MaterialData::SpecularColor, GetSpecularColor());
matData->SetParameter(MaterialData::SrcBlend, int(GetSrcBlend()));
matData->SetParameter(MaterialData::SrcBlend, static_cast<long long>(GetSrcBlend()));
// RendererParameter
matData->SetParameter(MaterialData::Blending, IsBlendingEnabled());
@@ -299,29 +299,29 @@ namespace Nz
matData->SetParameter(MaterialData::StencilTest, IsStencilTestEnabled());
// Samplers
matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, int(GetDiffuseSampler().GetAnisotropicLevel()));
matData->SetParameter(MaterialData::DiffuseFilter, int(GetDiffuseSampler().GetFilterMode()));
matData->SetParameter(MaterialData::DiffuseWrap, int(GetDiffuseSampler().GetWrapMode()));
matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, static_cast<long long>(GetDiffuseSampler().GetAnisotropicLevel()));
matData->SetParameter(MaterialData::DiffuseFilter, static_cast<long long>(GetDiffuseSampler().GetFilterMode()));
matData->SetParameter(MaterialData::DiffuseWrap, static_cast<long long>(GetDiffuseSampler().GetWrapMode()));
matData->SetParameter(MaterialData::SpecularAnisotropyLevel, int(GetSpecularSampler().GetAnisotropicLevel()));
matData->SetParameter(MaterialData::SpecularFilter, int(GetSpecularSampler().GetFilterMode()));
matData->SetParameter(MaterialData::SpecularWrap, int(GetSpecularSampler().GetWrapMode()));
matData->SetParameter(MaterialData::SpecularAnisotropyLevel, static_cast<long long>(GetSpecularSampler().GetAnisotropicLevel()));
matData->SetParameter(MaterialData::SpecularFilter, static_cast<long long>(GetSpecularSampler().GetFilterMode()));
matData->SetParameter(MaterialData::SpecularWrap, static_cast<long long>(GetSpecularSampler().GetWrapMode()));
// Stencil
matData->SetParameter(MaterialData::StencilCompare, int(GetPipelineInfo().stencilCompare.front));
matData->SetParameter(MaterialData::StencilFail, int(GetPipelineInfo().stencilFail.front));
matData->SetParameter(MaterialData::StencilPass, int(GetPipelineInfo().stencilPass.front));
matData->SetParameter(MaterialData::StencilZFail, int(GetPipelineInfo().stencilDepthFail.front));
matData->SetParameter(MaterialData::StencilMask, int(GetPipelineInfo().stencilWriteMask.front));
matData->SetParameter(MaterialData::StencilReference, int(GetPipelineInfo().stencilReference.front));
matData->SetParameter(MaterialData::StencilCompare, static_cast<long long>(GetPipelineInfo().stencilCompare.front));
matData->SetParameter(MaterialData::StencilFail, static_cast<long long>(GetPipelineInfo().stencilFail.front));
matData->SetParameter(MaterialData::StencilPass, static_cast<long long>(GetPipelineInfo().stencilPass.front));
matData->SetParameter(MaterialData::StencilZFail, static_cast<long long>(GetPipelineInfo().stencilDepthFail.front));
matData->SetParameter(MaterialData::StencilMask, static_cast<long long>(GetPipelineInfo().stencilWriteMask.front));
matData->SetParameter(MaterialData::StencilReference, static_cast<long long>(GetPipelineInfo().stencilReference.front));
// Stencil (back)
matData->SetParameter(MaterialData::BackFaceStencilCompare, int(GetPipelineInfo().stencilCompare.back));
matData->SetParameter(MaterialData::BackFaceStencilFail, int(GetPipelineInfo().stencilFail.back));
matData->SetParameter(MaterialData::BackFaceStencilPass, int(GetPipelineInfo().stencilPass.back));
matData->SetParameter(MaterialData::BackFaceStencilZFail, int(GetPipelineInfo().stencilDepthFail.back));
matData->SetParameter(MaterialData::BackFaceStencilMask, int(GetPipelineInfo().stencilWriteMask.back));
matData->SetParameter(MaterialData::BackFaceStencilReference, int(GetPipelineInfo().stencilReference.back));
matData->SetParameter(MaterialData::BackFaceStencilCompare, static_cast<long long>(GetPipelineInfo().stencilCompare.back));
matData->SetParameter(MaterialData::BackFaceStencilFail, static_cast<long long>(GetPipelineInfo().stencilFail.back));
matData->SetParameter(MaterialData::BackFaceStencilPass, static_cast<long long>(GetPipelineInfo().stencilPass.back));
matData->SetParameter(MaterialData::BackFaceStencilZFail, static_cast<long long>(GetPipelineInfo().stencilDepthFail.back));
matData->SetParameter(MaterialData::BackFaceStencilMask, static_cast<long long>(GetPipelineInfo().stencilWriteMask.back));
matData->SetParameter(MaterialData::BackFaceStencilReference, static_cast<long long>(GetPipelineInfo().stencilReference.back));
// Textures
if (HasAlphaMap())

View File

@@ -0,0 +1,56 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Lua scripting module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Lua/LuaCoroutine.hpp>
#include <Lua/lauxlib.h>
#include <Lua/lua.h>
#include <Lua/lualib.h>
#include <Nazara/Lua/LuaInstance.hpp>
#include <Nazara/Lua/Debug.hpp>
namespace Nz
{
LuaCoroutine::LuaCoroutine(lua_State* internalState, int refIndex) :
LuaState(internalState),
m_ref(refIndex)
{
}
LuaCoroutine::~LuaCoroutine()
{
if (m_ref >= 0)
DestroyReference(m_ref);
}
bool LuaCoroutine::CanResume() const
{
return lua_status(m_state) == LUA_YIELD;
}
Ternary LuaCoroutine::Resume(unsigned int argCount)
{
LuaInstance& instance = GetInstance(m_state);
if (instance.m_level++ == 0)
instance.m_clock.Restart();
int status = lua_resume(m_state, nullptr, argCount);
instance.m_level--;
if (status == LUA_OK)
return Ternary_True;
else if (status == LUA_YIELD)
return Ternary_Unknown;
else
{
m_lastError = ToString(-1);
Pop();
return Ternary_False;
}
}
bool LuaCoroutine::Run(int argCount, int /*resultCount*/)
{
return Resume(argCount) != Ternary_False;
}
}

View File

@@ -12,6 +12,7 @@
#include <Nazara/Core/MemoryHelper.hpp>
#include <Nazara/Core/MemoryView.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <cassert>
#include <cstdlib>
#include <stdexcept>
#include <unordered_map>
@@ -21,117 +22,16 @@ namespace Nz
{
namespace
{
LuaType FromLuaType(int type)
int AtPanic(lua_State* internalState)
{
switch (type)
{
case LUA_TBOOLEAN:
return LuaType_Boolean;
case LUA_TFUNCTION:
return LuaType_Function;
case LUA_TLIGHTUSERDATA:
return LuaType_LightUserdata;
case LUA_TNIL:
return LuaType_Nil;
case LUA_TNONE:
return LuaType_None;
case LUA_TNUMBER:
return LuaType_Number;
case LUA_TSTRING:
return LuaType_String;
case LUA_TTABLE:
return LuaType_Table;
case LUA_TTHREAD:
return LuaType_Thread;
case LUA_TUSERDATA:
return LuaType_Userdata;
default:
return LuaType_None;
}
}
struct StreamData
{
Stream* stream;
char buffer[NAZARA_CORE_FILE_BUFFERSIZE];
};
int AtPanic(lua_State* state)
{
String lastError(lua_tostring(state, -1));
String lastError(lua_tostring(internalState, -1));
throw std::runtime_error("Lua panic: " + lastError);
}
const char* StreamReader(lua_State* state, void* data, std::size_t* size)
{
NazaraUnused(state);
StreamData* streamData = static_cast<StreamData*>(data);
if (streamData->stream->EndOfStream())
return nullptr;
else
{
*size = streamData->stream->Read(streamData->buffer, NAZARA_CORE_FILE_BUFFERSIZE);
return streamData->buffer;
}
}
int s_comparisons[] = {
LUA_OPEQ, // LuaComparison_Equality
LUA_OPLT, // LuaComparison_Less
LUA_OPLE // LuaComparison_LessOrEqual
};
static_assert(sizeof(s_comparisons)/sizeof(int) == LuaComparison_Max+1, "Lua comparison array is incomplete");
int s_operations[] = {
LUA_OPADD, // LuaOperation_Addition
LUA_OPBAND, // LuaOperation_BitwiseAnd
LUA_OPSHL, // LuaOperation_BitwiseLeftShift
LUA_OPBNOT, // LuaOperation_BitwiseNot
LUA_OPBOR, // LuaOperation_BitwiseOr
LUA_OPSHR, // LuaOperation_BitwiseRightShift
LUA_OPBXOR, // LuaOperation_BitwiseXOr
LUA_OPDIV, // LuaOperation_Division
LUA_OPPOW, // LuaOperation_Exponentiation
LUA_OPIDIV, // LuaOperation_FloorDivision
LUA_OPMUL, // LuaOperation_Multiplication
LUA_OPMOD, // LuaOperation_Modulo
LUA_OPUNM, // LuaOperation_Negation
LUA_OPSUB // LuaOperation_Substraction
};
static_assert(sizeof(s_operations)/sizeof(int) == LuaOperation_Max+1, "Lua operation array is incomplete");
int s_types[] = {
LUA_TBOOLEAN, // LuaType_Boolean
LUA_TFUNCTION, // LuaType_Function
LUA_TLIGHTUSERDATA, // LuaType_LightUserdata
LUA_TNIL, // LuaType_Nil
LUA_TNUMBER, // LuaType_Number
LUA_TNONE, // LuaType_None
LUA_TSTRING, // LuaType_String
LUA_TTABLE, // LuaType_Table
LUA_TTHREAD, // LuaType_Thread
LUA_TUSERDATA // LuaType_Userdata
};
static_assert(sizeof(s_types)/sizeof(int) == LuaType_Max+1, "Lua type array is incomplete");
}
LuaInstance::LuaInstance() :
LuaState(nullptr),
m_memoryLimit(0),
m_memoryUsage(0),
m_timeLimit(1000),
@@ -143,738 +43,28 @@ namespace Nz
luaL_openlibs(m_state);
}
LuaInstance::LuaInstance(LuaInstance&& instance) noexcept :
m_memoryLimit(instance.m_memoryLimit),
m_memoryUsage(instance.m_memoryUsage),
m_timeLimit(instance.m_timeLimit),
m_clock(std::move(instance.m_clock)),
m_lastError(std::move(instance.m_lastError)),
m_state(instance.m_state),
m_level(instance.m_level)
{
instance.m_state = nullptr;
lua_setallocf(m_state, MemoryAllocator, this);
}
LuaInstance::~LuaInstance()
{
if (m_state)
lua_close(m_state);
}
void LuaInstance::ArgCheck(bool condition, unsigned int argNum, const char* error) const
inline void LuaInstance::SetMemoryUsage(std::size_t memoryUsage)
{
luaL_argcheck(m_state, condition, argNum, error);
}
void LuaInstance::ArgCheck(bool condition, unsigned int argNum, const String& error) const
{
luaL_argcheck(m_state, condition, argNum, error.GetConstBuffer());
}
int LuaInstance::ArgError(unsigned int argNum, const char* error) const
{
return luaL_argerror(m_state, argNum, error);
}
int LuaInstance::ArgError(unsigned int argNum, const String& error) const
{
return luaL_argerror(m_state, argNum, error.GetConstBuffer());
}
bool LuaInstance::Call(unsigned int argCount)
{
return Run(argCount, LUA_MULTRET);
}
bool LuaInstance::Call(unsigned int argCount, unsigned int resultCount)
{
return Run(argCount, resultCount);
}
void LuaInstance::CheckAny(int index) const
{
luaL_checkany(m_state, index);
}
bool LuaInstance::CheckBoolean(int index) const
{
if (lua_isnoneornil(m_state, index))
{
const char* msg = lua_pushfstring(m_state, "%s expected, got %s", lua_typename(m_state, LUA_TBOOLEAN), luaL_typename(m_state, index));
luaL_argerror(m_state, index, msg); // Lance une exception
return false;
}
return lua_toboolean(m_state, index) != 0;
}
bool LuaInstance::CheckBoolean(int index, bool defValue) const
{
if (lua_isnoneornil(m_state, index))
return defValue;
return lua_toboolean(m_state, index) != 0;
}
long long LuaInstance::CheckInteger(int index) const
{
return luaL_checkinteger(m_state, index);
}
long long LuaInstance::CheckInteger(int index, long long defValue) const
{
return luaL_optinteger(m_state, index, defValue);
}
double LuaInstance::CheckNumber(int index) const
{
return luaL_checknumber(m_state, index);
}
double LuaInstance::CheckNumber(int index, double defValue) const
{
return luaL_optnumber(m_state, index, defValue);
}
void LuaInstance::CheckStack(int space, const char* error) const
{
luaL_checkstack(m_state, space, error);
}
void LuaInstance::CheckStack(int space, const String& error) const
{
CheckStack(space, error.GetConstBuffer());
}
const char* LuaInstance::CheckString(int index, std::size_t* length) const
{
return luaL_checklstring(m_state, index, length);
}
const char* LuaInstance::CheckString(int index, const char* defValue, std::size_t* length) const
{
return luaL_optlstring(m_state, index, defValue, length);
}
void LuaInstance::CheckType(int index, LuaType type) const
{
#ifdef NAZARA_DEBUG
if (type > LuaType_Max)
{
NazaraError("Lua type out of enum");
return;
}
#endif
luaL_checktype(m_state, index, s_types[type]);
}
void* LuaInstance::CheckUserdata(int index, const char* tname) const
{
return luaL_checkudata(m_state, index, tname);
}
void* LuaInstance::CheckUserdata(int index, const String& tname) const
{
return luaL_checkudata(m_state, index, tname.GetConstBuffer());
}
bool LuaInstance::Compare(int index1, int index2, LuaComparison comparison) const
{
#ifdef NAZARA_DEBUG
if (comparison > LuaComparison_Max)
{
NazaraError("Lua comparison out of enum");
return false;
}
#endif
return (lua_compare(m_state, index1, index2, s_comparisons[comparison]) != 0);
}
void LuaInstance::Compute(LuaOperation operation) const
{
#ifdef NAZARA_DEBUG
if (operation > LuaOperation_Max)
{
NazaraError("Lua operation out of enum");
return;
}
#endif
lua_arith(m_state, s_operations[operation]);
}
void LuaInstance::Concatenate(int count) const
{
lua_concat(m_state, count);
}
int LuaInstance::CreateReference()
{
return luaL_ref(m_state, LUA_REGISTRYINDEX);
}
void LuaInstance::DestroyReference(int ref)
{
luaL_unref(m_state, LUA_REGISTRYINDEX, ref);
}
String LuaInstance::DumpStack() const
{
StringStream stream;
unsigned int stackTop = GetStackTop();
stream << stackTop << " entries\n";
for (unsigned int i = 1; i <= stackTop; ++i)
{
stream << i << ": ";
switch (GetType(i))
{
case LuaType_Boolean:
stream << "Boolean(" << ToBoolean(i) << ')';
break;
case LuaType_Function:
stream << "Function(" << ToPointer(i) << ')';
break;
case LuaType_LightUserdata:
case LuaType_Userdata:
stream << "Userdata(" << ToUserdata(i) << ')';
break;
case LuaType_Nil:
stream << "Nil";
break;
case LuaType_None:
stream << "None";
break;
case LuaType_Number:
stream << "Number(" << ToNumber(i) << ')';
break;
case LuaType_String:
stream << "String(" << ToString(i) << ')';
break;
case LuaType_Table:
stream << "Table(" << ToPointer(i) << ')';
break;
case LuaType_Thread:
stream << "Thread(" << ToPointer(i) << ')';
break;
default:
stream << "Unknown(" << ToPointer(i) << ')';
break;
}
stream << '\n';
}
return stream.ToString();
}
void LuaInstance::Error(const char* message) const
{
luaL_error(m_state, message);
}
void LuaInstance::Error(const String& message) const
{
luaL_error(m_state, message.GetConstBuffer());
}
bool LuaInstance::Execute(const String& code)
{
if (code.IsEmpty())
return true;
if (luaL_loadstring(m_state, code.GetConstBuffer()) != 0)
{
m_lastError = lua_tostring(m_state, -1);
lua_pop(m_state, 1);
return false;
}
return Run(0, 0);
}
bool LuaInstance::ExecuteFromFile(const String& filePath)
{
File file(filePath);
if (!file.Open(OpenMode_ReadOnly | OpenMode_Text))
{
NazaraError("Failed to open file");
return false;
}
std::size_t length = static_cast<std::size_t>(file.GetSize());
String source(length, '\0');
if (file.Read(&source[0], length) != length)
{
NazaraError("Failed to read file");
return false;
}
file.Close();
return Execute(source);
}
bool LuaInstance::ExecuteFromMemory(const void* data, std::size_t size)
{
MemoryView stream(data, size);
return ExecuteFromStream(stream);
}
bool LuaInstance::ExecuteFromStream(Stream& stream)
{
StreamData data;
data.stream = &stream;
if (lua_load(m_state, StreamReader, &data, "C++", nullptr) != 0)
{
m_lastError = lua_tostring(m_state, -1);
lua_pop(m_state, 1);
return false;
}
return Run(0, 0);
}
int LuaInstance::GetAbsIndex(int index) const
{
return lua_absindex(m_state, index);
}
LuaType LuaInstance::GetField(const char* fieldName, int tableIndex) const
{
return FromLuaType(lua_getfield(m_state, tableIndex, fieldName));
}
LuaType LuaInstance::GetField(const String& fieldName, int tableIndex) const
{
return FromLuaType(lua_getfield(m_state, tableIndex, fieldName.GetConstBuffer()));
}
LuaType LuaInstance::GetGlobal(const char* name) const
{
return FromLuaType(lua_getglobal(m_state, name));
}
LuaType LuaInstance::GetGlobal(const String& name) const
{
return FromLuaType(lua_getglobal(m_state, name.GetConstBuffer()));
}
LuaType LuaInstance::GetMetatable(const char* tname) const
{
return FromLuaType(luaL_getmetatable(m_state, tname));
}
LuaType LuaInstance::GetMetatable(const String& tname) const
{
return FromLuaType(luaL_getmetatable(m_state, tname.GetConstBuffer()));
}
bool LuaInstance::GetMetatable(int index) const
{
return lua_getmetatable(m_state, index) != 0;
}
unsigned int LuaInstance::GetStackTop() const
{
return static_cast<int>(lua_gettop(m_state));
}
LuaType LuaInstance::GetTable(int index) const
{
return FromLuaType(lua_gettable(m_state, index));
}
LuaType LuaInstance::GetType(int index) const
{
return FromLuaType(lua_type(m_state, index));
}
const char* LuaInstance::GetTypeName(LuaType type) const
{
#ifdef NAZARA_DEBUG
if (type > LuaType_Max)
{
NazaraError("Lua type out of enum");
return nullptr;
}
#endif
return lua_typename(m_state, s_types[type]);
}
void LuaInstance::Insert(int index) const
{
lua_insert(m_state, index);
}
bool LuaInstance::IsOfType(int index, LuaType type) const
{
switch (type)
{
case LuaType_Boolean:
return lua_isboolean(m_state, index) != 0;
case LuaType_Function:
return lua_isfunction(m_state, index) != 0;
case LuaType_LightUserdata:
return lua_islightuserdata(m_state, index) != 0;
case LuaType_Nil:
return lua_isnil(m_state, index) != 0;
case LuaType_None:
return lua_isnone(m_state, index) != 0;
case LuaType_Number:
return lua_isnumber(m_state, index) != 0;
case LuaType_String:
return lua_isstring(m_state, index) != 0;
case LuaType_Table:
return lua_istable(m_state, index) != 0;
case LuaType_Thread:
return lua_isthread(m_state, index) != 0;
case LuaType_Userdata:
return lua_isuserdata(m_state, index) != 0;
}
NazaraError("Lua type not handled (0x" + String::Number(type, 16) + ')');
return false;
}
bool LuaInstance::IsOfType(int index, const char* tname) const
{
void* ud = luaL_testudata(m_state, index, tname);
return ud != nullptr;
}
bool LuaInstance::IsOfType(int index, const String& tname) const
{
return IsOfType(index, tname.GetConstBuffer());
}
bool LuaInstance::IsValid(int index) const
{
return lua_isnoneornil(m_state, index) == 0;
}
long long LuaInstance::Length(int index) const
{
return luaL_len(m_state, index);
}
void LuaInstance::MoveTo(LuaInstance* instance, int n) const
{
lua_xmove(m_state, instance->m_state, n);
}
bool LuaInstance::NewMetatable(const char* str)
{
return luaL_newmetatable(m_state, str) != 0;
}
bool LuaInstance::NewMetatable(const String& str)
{
return luaL_newmetatable(m_state, str.GetConstBuffer()) != 0;
}
bool LuaInstance::Next(int index) const
{
return lua_next(m_state, index) != 0;
}
void LuaInstance::Pop(unsigned int n) const
{
lua_pop(m_state, static_cast<int>(n));
}
void LuaInstance::PushBoolean(bool value) const
{
lua_pushboolean(m_state, (value) ? 1 : 0);
}
void LuaInstance::PushCFunction(LuaCFunction func, unsigned int upvalueCount) const
{
lua_pushcclosure(m_state, func, upvalueCount);
}
void LuaInstance::PushFunction(LuaFunction func) const
{
LuaFunction* luaFunc = static_cast<LuaFunction*>(lua_newuserdata(m_state, sizeof(LuaFunction)));
PlacementNew(luaFunc, std::move(func));
lua_pushcclosure(m_state, ProxyFunc, 1);
}
void LuaInstance::PushInteger(long long value) const
{
lua_pushinteger(m_state, value);
}
void LuaInstance::PushLightUserdata(void* value) const
{
lua_pushlightuserdata(m_state, value);
}
void LuaInstance::PushMetatable(const char* str) const
{
luaL_getmetatable(m_state, str);
}
void LuaInstance::PushMetatable(const String& str) const
{
luaL_getmetatable(m_state, str.GetConstBuffer());
}
void LuaInstance::PushNil() const
{
lua_pushnil(m_state);
}
void LuaInstance::PushNumber(double value) const
{
lua_pushnumber(m_state, value);
}
void LuaInstance::PushReference(int ref) const
{
lua_rawgeti(m_state, LUA_REGISTRYINDEX, ref);
}
void LuaInstance::PushString(const char* str) const
{
lua_pushstring(m_state, str);
}
void LuaInstance::PushString(const char* str, std::size_t size) const
{
lua_pushlstring(m_state, str, size);
}
void LuaInstance::PushString(const String& str) const
{
lua_pushlstring(m_state, str.GetConstBuffer(), str.GetSize());
}
void LuaInstance::PushTable(std::size_t sequenceElementCount, std::size_t arrayElementCount) const
{
constexpr std::size_t maxInt = std::numeric_limits<int>::max();
lua_createtable(m_state, static_cast<int>(std::min(sequenceElementCount, maxInt)), static_cast<int>(std::min(arrayElementCount, maxInt)));
}
void* LuaInstance::PushUserdata(std::size_t size) const
{
return lua_newuserdata(m_state, size);
}
void LuaInstance::PushValue(int index) const
{
lua_pushvalue(m_state, index);
}
void LuaInstance::Remove(int index) const
{
lua_remove(m_state, index);
}
void LuaInstance::Replace(int index) const
{
lua_replace(m_state, index);
}
void LuaInstance::SetField(const char* name, int tableIndex) const
{
lua_setfield(m_state, tableIndex, name);
}
void LuaInstance::SetField(const String& name, int tableIndex) const
{
lua_setfield(m_state, tableIndex, name.GetConstBuffer());
}
void LuaInstance::SetGlobal(const char* name)
{
lua_setglobal(m_state, name);
}
void LuaInstance::SetGlobal(const String& name)
{
lua_setglobal(m_state, name.GetConstBuffer());
}
void LuaInstance::SetMetatable(const char* tname) const
{
luaL_setmetatable(m_state, tname);
}
void LuaInstance::SetMetatable(const String& tname) const
{
luaL_setmetatable(m_state, tname.GetConstBuffer());
}
void LuaInstance::SetMetatable(int index) const
{
lua_setmetatable(m_state, index);
}
void LuaInstance::SetMemoryLimit(std::size_t memoryLimit)
{
m_memoryLimit = memoryLimit;
}
void LuaInstance::SetTable(int index) const
{
lua_settable(m_state, index);
}
void LuaInstance::SetTimeLimit(UInt32 timeLimit)
{
if (m_timeLimit != timeLimit)
{
if (m_timeLimit == 0)
lua_sethook(m_state, TimeLimiter, LUA_MASKCOUNT, 1000);
else if (timeLimit == 0)
lua_sethook(m_state, TimeLimiter, 0, 1000);
m_timeLimit = timeLimit;
}
}
bool LuaInstance::ToBoolean(int index) const
{
return lua_toboolean(m_state, index) != 0;
}
long long LuaInstance::ToInteger(int index, bool* succeeded) const
{
int success;
long long result = lua_tointegerx(m_state, index, &success);
if (succeeded)
*succeeded = (success != 0);
return result;
}
double LuaInstance::ToNumber(int index, bool* succeeded) const
{
int success;
double result = lua_tonumberx(m_state, index, &success);
if (succeeded)
*succeeded = (success != 0);
return result;
}
const void* LuaInstance::ToPointer(int index) const
{
return lua_topointer(m_state, index);
}
const char* LuaInstance::ToString(int index, std::size_t* length) const
{
return lua_tolstring(m_state, index, length);
}
void* LuaInstance::ToUserdata(int index) const
{
return lua_touserdata(m_state, index);
}
void* LuaInstance::ToUserdata(int index, const char* tname) const
{
return luaL_testudata(m_state, index, tname);
}
void* LuaInstance::ToUserdata(int index, const String& tname) const
{
return luaL_testudata(m_state, index, tname.GetConstBuffer());
}
LuaInstance& LuaInstance::operator=(LuaInstance&& instance) noexcept
{
m_clock = std::move(instance.m_clock);
m_lastError = std::move(instance.m_lastError);
m_level = instance.m_level;
m_memoryLimit = instance.m_memoryLimit;
m_memoryUsage = instance.m_memoryUsage;
m_state = instance.m_state;
m_timeLimit = instance.m_timeLimit;
instance.m_state = nullptr;
// Update allocator pointer
lua_setallocf(m_state, MemoryAllocator, this);
return *this;
}
int LuaInstance::GetIndexOfUpValue(int upValue)
{
return lua_upvalueindex(upValue);
}
LuaInstance* LuaInstance::GetInstance(lua_State* state)
{
LuaInstance* instance;
lua_getallocf(state, reinterpret_cast<void**>(&instance));
return instance;
}
bool LuaInstance::Run(int argCount, int resultCount)
{
if (m_level++ == 0)
m_clock.Restart();
int status = lua_pcall(m_state, argCount, resultCount, 0);
m_level--;
if (status != 0)
{
m_lastError = lua_tostring(m_state, -1);
lua_pop(m_state, 1);
return false;
}
return true;
m_memoryUsage = memoryUsage;
}
void* LuaInstance::MemoryAllocator(void* ud, void* ptr, std::size_t osize, std::size_t nsize)
{
LuaInstance* instance = static_cast<LuaInstance*>(ud);
std::size_t& memoryLimit = instance->m_memoryLimit;
std::size_t& memoryUsage = instance->m_memoryUsage;
std::size_t memoryLimit = instance->GetMemoryLimit();
std::size_t memoryUsage = instance->GetMemoryUsage();
if (nsize == 0)
{
memoryUsage -= osize;
assert(memoryUsage >= osize);
instance->SetMemoryUsage(memoryUsage - osize);
std::free(ptr);
return nullptr;
@@ -891,24 +81,20 @@ namespace Nz
return nullptr;
}
memoryUsage = usage;
instance->SetMemoryUsage(usage);
return std::realloc(ptr, nsize);
}
}
int LuaInstance::ProxyFunc(lua_State* state)
{
LuaFunction& func = *static_cast<LuaFunction*>(lua_touserdata(state, lua_upvalueindex(1)));
return func(*GetInstance(state));
}
void LuaInstance::TimeLimiter(lua_State* state, lua_Debug* debug)
void LuaInstance::TimeLimiter(lua_State* internalState, lua_Debug* debug)
{
NazaraUnused(debug);
LuaInstance* instance = GetInstance(state);
if (instance->m_clock.GetMilliseconds() > instance->m_timeLimit)
luaL_error(state, "maximum execution time exceeded");
LuaInstance* instance;
lua_getallocf(internalState, reinterpret_cast<void**>(&instance));
if (instance->m_clock.GetMilliseconds() > instance->GetTimeLimit())
luaL_error(internalState, "maximum execution time exceeded");
}
}

843
src/Nazara/Lua/LuaState.cpp Normal file
View File

@@ -0,0 +1,843 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Lua scripting module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Lua/LuaState.hpp>
#include <Lua/lauxlib.h>
#include <Lua/lua.h>
#include <Lua/lualib.h>
#include <Nazara/Core/Clock.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/MemoryHelper.hpp>
#include <Nazara/Core/MemoryView.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <Nazara/Lua/LuaCoroutine.hpp>
#include <Nazara/Lua/LuaInstance.hpp>
#include <cstdlib>
#include <stdexcept>
#include <unordered_map>
#include <Nazara/Lua/Debug.hpp>
namespace Nz
{
namespace
{
LuaType FromLuaType(int type)
{
switch (type)
{
case LUA_TBOOLEAN:
return LuaType_Boolean;
case LUA_TFUNCTION:
return LuaType_Function;
case LUA_TLIGHTUSERDATA:
return LuaType_LightUserdata;
case LUA_TNIL:
return LuaType_Nil;
case LUA_TNONE:
return LuaType_None;
case LUA_TNUMBER:
return LuaType_Number;
case LUA_TSTRING:
return LuaType_String;
case LUA_TTABLE:
return LuaType_Table;
case LUA_TTHREAD:
return LuaType_Thread;
case LUA_TUSERDATA:
return LuaType_Userdata;
default:
return LuaType_None;
}
}
struct StreamData
{
Stream* stream;
char buffer[NAZARA_CORE_FILE_BUFFERSIZE];
};
const char* StreamReader(lua_State* internalState, void* data, std::size_t* size)
{
NazaraUnused(internalState);
StreamData* streamData = static_cast<StreamData*>(data);
if (streamData->stream->EndOfStream())
return nullptr;
else
{
*size = streamData->stream->Read(streamData->buffer, NAZARA_CORE_FILE_BUFFERSIZE);
return streamData->buffer;
}
}
int s_comparisons[] = {
LUA_OPEQ, // LuaComparison_Equality
LUA_OPLT, // LuaComparison_Less
LUA_OPLE // LuaComparison_LessOrEqual
};
static_assert(sizeof(s_comparisons)/sizeof(int) == LuaComparison_Max+1, "Lua comparison array is incomplete");
int s_operations[] = {
LUA_OPADD, // LuaOperation_Addition
LUA_OPBAND, // LuaOperation_BitwiseAnd
LUA_OPSHL, // LuaOperation_BitwiseLeftShift
LUA_OPBNOT, // LuaOperation_BitwiseNot
LUA_OPBOR, // LuaOperation_BitwiseOr
LUA_OPSHR, // LuaOperation_BitwiseRightShift
LUA_OPBXOR, // LuaOperation_BitwiseXOr
LUA_OPDIV, // LuaOperation_Division
LUA_OPPOW, // LuaOperation_Exponentiation
LUA_OPIDIV, // LuaOperation_FloorDivision
LUA_OPMUL, // LuaOperation_Multiplication
LUA_OPMOD, // LuaOperation_Modulo
LUA_OPUNM, // LuaOperation_Negation
LUA_OPSUB // LuaOperation_Substraction
};
static_assert(sizeof(s_operations)/sizeof(int) == LuaOperation_Max+1, "Lua operation array is incomplete");
int s_types[] = {
LUA_TBOOLEAN, // LuaType_Boolean
LUA_TFUNCTION, // LuaType_Function
LUA_TLIGHTUSERDATA, // LuaType_LightUserdata
LUA_TNIL, // LuaType_Nil
LUA_TNUMBER, // LuaType_Number
LUA_TNONE, // LuaType_None
LUA_TSTRING, // LuaType_String
LUA_TTABLE, // LuaType_Table
LUA_TTHREAD, // LuaType_Thread
LUA_TUSERDATA // LuaType_Userdata
};
static_assert(sizeof(s_types)/sizeof(int) == LuaType_Max+1, "Lua type array is incomplete");
}
LuaState::LuaState(LuaState&& state) noexcept :
m_lastError(state.m_lastError),
m_state(state.m_state)
{
}
void LuaState::ArgCheck(bool condition, unsigned int argNum, const char* error) const
{
luaL_argcheck(m_state, condition, argNum, error);
}
void LuaState::ArgCheck(bool condition, unsigned int argNum, const String& error) const
{
luaL_argcheck(m_state, condition, argNum, error.GetConstBuffer());
}
int LuaState::ArgError(unsigned int argNum, const char* error) const
{
return luaL_argerror(m_state, argNum, error);
}
int LuaState::ArgError(unsigned int argNum, const String& error) const
{
return luaL_argerror(m_state, argNum, error.GetConstBuffer());
}
bool LuaState::Call(unsigned int argCount)
{
return Run(argCount, LUA_MULTRET);
}
bool LuaState::Call(unsigned int argCount, unsigned int resultCount)
{
return Run(argCount, resultCount);
}
void LuaState::CheckAny(int index) const
{
luaL_checkany(m_state, index);
}
bool LuaState::CheckBoolean(int index) const
{
if (lua_isnoneornil(m_state, index))
{
const char* msg = lua_pushfstring(m_state, "%s expected, got %s", lua_typename(m_state, LUA_TBOOLEAN), luaL_typename(m_state, index));
luaL_argerror(m_state, index, msg); // Lance une exception
return false;
}
return lua_toboolean(m_state, index) != 0;
}
bool LuaState::CheckBoolean(int index, bool defValue) const
{
if (lua_isnoneornil(m_state, index))
return defValue;
return lua_toboolean(m_state, index) != 0;
}
long long LuaState::CheckInteger(int index) const
{
return luaL_checkinteger(m_state, index);
}
long long LuaState::CheckInteger(int index, long long defValue) const
{
return luaL_optinteger(m_state, index, defValue);
}
double LuaState::CheckNumber(int index) const
{
return luaL_checknumber(m_state, index);
}
double LuaState::CheckNumber(int index, double defValue) const
{
return luaL_optnumber(m_state, index, defValue);
}
void LuaState::CheckStack(int space, const char* error) const
{
luaL_checkstack(m_state, space, error);
}
void LuaState::CheckStack(int space, const String& error) const
{
CheckStack(space, error.GetConstBuffer());
}
const char* LuaState::CheckString(int index, std::size_t* length) const
{
return luaL_checklstring(m_state, index, length);
}
const char* LuaState::CheckString(int index, const char* defValue, std::size_t* length) const
{
return luaL_optlstring(m_state, index, defValue, length);
}
void LuaState::CheckType(int index, LuaType type) const
{
#ifdef NAZARA_DEBUG
if (type > LuaType_Max)
{
NazaraError("Lua type out of enum");
return;
}
#endif
luaL_checktype(m_state, index, s_types[type]);
}
void* LuaState::CheckUserdata(int index, const char* tname) const
{
return luaL_checkudata(m_state, index, tname);
}
void* LuaState::CheckUserdata(int index, const String& tname) const
{
return luaL_checkudata(m_state, index, tname.GetConstBuffer());
}
bool LuaState::Compare(int index1, int index2, LuaComparison comparison) const
{
#ifdef NAZARA_DEBUG
if (comparison > LuaComparison_Max)
{
NazaraError("Lua comparison out of enum");
return false;
}
#endif
return (lua_compare(m_state, index1, index2, s_comparisons[comparison]) != 0);
}
void LuaState::Compute(LuaOperation operation) const
{
#ifdef NAZARA_DEBUG
if (operation > LuaOperation_Max)
{
NazaraError("Lua operation out of enum");
return;
}
#endif
lua_arith(m_state, s_operations[operation]);
}
void LuaState::Concatenate(int count) const
{
lua_concat(m_state, count);
}
int LuaState::CreateReference()
{
return luaL_ref(m_state, LUA_REGISTRYINDEX);
}
void LuaState::DestroyReference(int ref)
{
luaL_unref(m_state, LUA_REGISTRYINDEX, ref);
}
String LuaState::DumpStack() const
{
StringStream stream;
unsigned int stackTop = GetStackTop();
stream << stackTop << " entries\n";
for (unsigned int i = 1; i <= stackTop; ++i)
{
stream << i << ": ";
switch (GetType(i))
{
case LuaType_Boolean:
stream << "Boolean(" << ToBoolean(i) << ')';
break;
case LuaType_Function:
stream << "Function(" << ToPointer(i) << ')';
break;
case LuaType_LightUserdata:
case LuaType_Userdata:
stream << "Userdata(" << ToUserdata(i) << ')';
break;
case LuaType_Nil:
stream << "Nil";
break;
case LuaType_None:
stream << "None";
break;
case LuaType_Number:
stream << "Number(" << ToNumber(i) << ')';
break;
case LuaType_String:
stream << "String(" << ToString(i) << ')';
break;
case LuaType_Table:
stream << "Table(" << ToPointer(i) << ')';
break;
case LuaType_Thread:
stream << "Thread(" << ToPointer(i) << ')';
break;
default:
stream << "Unknown(" << ToPointer(i) << ')';
break;
}
stream << '\n';
}
return stream.ToString();
}
void LuaState::Error(const char* message) const
{
luaL_error(m_state, message);
}
void LuaState::Error(const String& message) const
{
luaL_error(m_state, message.GetConstBuffer());
}
bool LuaState::Execute(const String& code)
{
if (code.IsEmpty())
return true;
if (luaL_loadstring(m_state, code.GetConstBuffer()) != 0)
{
m_lastError = lua_tostring(m_state, -1);
lua_pop(m_state, 1);
return false;
}
return Run(0, 0);
}
bool LuaState::ExecuteFromFile(const String& filePath)
{
File file(filePath);
if (!file.Open(OpenMode_ReadOnly | OpenMode_Text))
{
NazaraError("Failed to open file");
return false;
}
std::size_t length = static_cast<std::size_t>(file.GetSize());
String source(length, '\0');
if (file.Read(&source[0], length) != length)
{
NazaraError("Failed to read file");
return false;
}
file.Close();
return Execute(source);
}
bool LuaState::ExecuteFromMemory(const void* data, std::size_t size)
{
MemoryView stream(data, size);
return ExecuteFromStream(stream);
}
bool LuaState::ExecuteFromStream(Stream& stream)
{
StreamData data;
data.stream = &stream;
if (lua_load(m_state, StreamReader, &data, "C++", nullptr) != 0)
{
m_lastError = lua_tostring(m_state, -1);
lua_pop(m_state, 1);
return false;
}
return Run(0, 0);
}
int LuaState::GetAbsIndex(int index) const
{
return lua_absindex(m_state, index);
}
LuaType LuaState::GetField(const char* fieldName, int tableIndex) const
{
return FromLuaType(lua_getfield(m_state, tableIndex, fieldName));
}
LuaType LuaState::GetField(const String& fieldName, int tableIndex) const
{
return FromLuaType(lua_getfield(m_state, tableIndex, fieldName.GetConstBuffer()));
}
LuaType LuaState::GetGlobal(const char* name) const
{
return FromLuaType(lua_getglobal(m_state, name));
}
LuaType LuaState::GetGlobal(const String& name) const
{
return FromLuaType(lua_getglobal(m_state, name.GetConstBuffer()));
}
LuaType LuaState::GetMetatable(const char* tname) const
{
return FromLuaType(luaL_getmetatable(m_state, tname));
}
LuaType LuaState::GetMetatable(const String& tname) const
{
return FromLuaType(luaL_getmetatable(m_state, tname.GetConstBuffer()));
}
bool LuaState::GetMetatable(int index) const
{
return lua_getmetatable(m_state, index) != 0;
}
unsigned int LuaState::GetStackTop() const
{
return static_cast<int>(lua_gettop(m_state));
}
LuaType LuaState::GetTable(int index) const
{
return FromLuaType(lua_gettable(m_state, index));
}
LuaType LuaState::GetTableRaw(int index) const
{
return FromLuaType(lua_rawget(m_state, index));
}
LuaType LuaState::GetType(int index) const
{
return FromLuaType(lua_type(m_state, index));
}
const char* LuaState::GetTypeName(LuaType type) const
{
#ifdef NAZARA_DEBUG
if (type > LuaType_Max)
{
NazaraError("Lua type out of enum");
return nullptr;
}
#endif
return lua_typename(m_state, s_types[type]);
}
void LuaState::Insert(int index) const
{
lua_insert(m_state, index);
}
bool LuaState::IsOfType(int index, LuaType type) const
{
switch (type)
{
case LuaType_Boolean:
return lua_isboolean(m_state, index) != 0;
case LuaType_Function:
return lua_isfunction(m_state, index) != 0;
case LuaType_LightUserdata:
return lua_islightuserdata(m_state, index) != 0;
case LuaType_Nil:
return lua_isnil(m_state, index) != 0;
case LuaType_None:
return lua_isnone(m_state, index) != 0;
case LuaType_Number:
return lua_isnumber(m_state, index) != 0;
case LuaType_String:
return lua_isstring(m_state, index) != 0;
case LuaType_Table:
return lua_istable(m_state, index) != 0;
case LuaType_Thread:
return lua_isthread(m_state, index) != 0;
case LuaType_Userdata:
return lua_isuserdata(m_state, index) != 0;
}
NazaraError("Lua type not handled (0x" + String::Number(type, 16) + ')');
return false;
}
bool LuaState::IsOfType(int index, const char* tname) const
{
void* ud = luaL_testudata(m_state, index, tname);
return ud != nullptr;
}
bool LuaState::IsOfType(int index, const String& tname) const
{
return IsOfType(index, tname.GetConstBuffer());
}
bool LuaState::IsValid(int index) const
{
return lua_isnoneornil(m_state, index) == 0;
}
long long LuaState::Length(int index) const
{
return luaL_len(m_state, index);
}
std::size_t LuaState::LengthRaw(int index) const
{
return lua_rawlen(m_state, index);
}
void LuaState::MoveTo(LuaState* instance, int n) const
{
lua_xmove(m_state, instance->m_state, n);
}
LuaCoroutine LuaState::NewCoroutine()
{
lua_State* thread = lua_newthread(m_state);
int ref = luaL_ref(m_state, LUA_REGISTRYINDEX);
return LuaCoroutine(thread, ref);
}
bool LuaState::NewMetatable(const char* str)
{
return luaL_newmetatable(m_state, str) != 0;
}
bool LuaState::NewMetatable(const String& str)
{
return luaL_newmetatable(m_state, str.GetConstBuffer()) != 0;
}
bool LuaState::Next(int index) const
{
return lua_next(m_state, index) != 0;
}
void LuaState::Pop(unsigned int n) const
{
lua_pop(m_state, static_cast<int>(n));
}
void LuaState::PushBoolean(bool value) const
{
lua_pushboolean(m_state, (value) ? 1 : 0);
}
void LuaState::PushCFunction(LuaCFunction func, unsigned int upvalueCount) const
{
lua_pushcclosure(m_state, func, upvalueCount);
}
void LuaState::PushFunction(LuaFunction func) const
{
LuaFunction* luaFunc = static_cast<LuaFunction*>(lua_newuserdata(m_state, sizeof(LuaFunction)));
PlacementNew(luaFunc, std::move(func));
lua_pushcclosure(m_state, ProxyFunc, 1);
}
void LuaState::PushInteger(long long value) const
{
lua_pushinteger(m_state, value);
}
void LuaState::PushLightUserdata(void* value) const
{
lua_pushlightuserdata(m_state, value);
}
void LuaState::PushMetatable(const char* str) const
{
luaL_getmetatable(m_state, str);
}
void LuaState::PushMetatable(const String& str) const
{
luaL_getmetatable(m_state, str.GetConstBuffer());
}
void LuaState::PushNil() const
{
lua_pushnil(m_state);
}
void LuaState::PushNumber(double value) const
{
lua_pushnumber(m_state, value);
}
void LuaState::PushReference(int ref) const
{
lua_rawgeti(m_state, LUA_REGISTRYINDEX, ref);
}
void LuaState::PushString(const char* str) const
{
lua_pushstring(m_state, str);
}
void LuaState::PushString(const char* str, std::size_t size) const
{
lua_pushlstring(m_state, str, size);
}
void LuaState::PushString(const String& str) const
{
lua_pushlstring(m_state, str.GetConstBuffer(), str.GetSize());
}
void LuaState::PushTable(std::size_t sequenceElementCount, std::size_t arrayElementCount) const
{
constexpr std::size_t maxInt = std::numeric_limits<int>::max();
lua_createtable(m_state, static_cast<int>(std::min(sequenceElementCount, maxInt)), static_cast<int>(std::min(arrayElementCount, maxInt)));
}
void* LuaState::PushUserdata(std::size_t size) const
{
return lua_newuserdata(m_state, size);
}
void LuaState::PushValue(int index) const
{
lua_pushvalue(m_state, index);
}
void LuaState::Remove(int index) const
{
lua_remove(m_state, index);
}
void LuaState::Replace(int index) const
{
lua_replace(m_state, index);
}
void LuaState::SetField(const char* name, int tableIndex) const
{
lua_setfield(m_state, tableIndex, name);
}
void LuaState::SetField(const String& name, int tableIndex) const
{
lua_setfield(m_state, tableIndex, name.GetConstBuffer());
}
void LuaState::SetGlobal(const char* name)
{
lua_setglobal(m_state, name);
}
void LuaState::SetGlobal(const String& name)
{
lua_setglobal(m_state, name.GetConstBuffer());
}
void LuaState::SetMetatable(const char* tname) const
{
luaL_setmetatable(m_state, tname);
}
void LuaState::SetMetatable(const String& tname) const
{
luaL_setmetatable(m_state, tname.GetConstBuffer());
}
void LuaState::SetMetatable(int index) const
{
lua_setmetatable(m_state, index);
}
void LuaState::SetTable(int index) const
{
lua_settable(m_state, index);
}
void LuaState::SetTableRaw(int index) const
{
lua_rawset(m_state, index);
}
bool LuaState::ToBoolean(int index) const
{
return lua_toboolean(m_state, index) != 0;
}
long long LuaState::ToInteger(int index, bool* succeeded) const
{
int success;
long long result = lua_tointegerx(m_state, index, &success);
if (succeeded)
*succeeded = (success != 0);
return result;
}
double LuaState::ToNumber(int index, bool* succeeded) const
{
int success;
double result = lua_tonumberx(m_state, index, &success);
if (succeeded)
*succeeded = (success != 0);
return result;
}
const void* LuaState::ToPointer(int index) const
{
return lua_topointer(m_state, index);
}
const char* LuaState::ToString(int index, std::size_t* length) const
{
return lua_tolstring(m_state, index, length);
}
void* LuaState::ToUserdata(int index) const
{
return lua_touserdata(m_state, index);
}
void* LuaState::ToUserdata(int index, const char* tname) const
{
return luaL_testudata(m_state, index, tname);
}
void* LuaState::ToUserdata(int index, const String& tname) const
{
return luaL_testudata(m_state, index, tname.GetConstBuffer());
}
LuaState& LuaState::operator=(LuaState&& state) noexcept
{
m_lastError = std::move(state.m_lastError);
m_state = state.m_state;
return *this;
}
bool LuaState::Run(int argCount, int resultCount)
{
LuaInstance& instance = GetInstance(m_state);
if (instance.m_level++ == 0)
instance.m_clock.Restart();
int status = lua_pcall(m_state, argCount, resultCount, 0);
instance.m_level--;
if (status != 0)
{
m_lastError = lua_tostring(m_state, -1);
lua_pop(m_state, 1);
return false;
}
return true;
}
int LuaState::GetIndexOfUpValue(int upValue)
{
return lua_upvalueindex(upValue);
}
LuaInstance& LuaState::GetInstance(lua_State* internalState)
{
LuaInstance* instance;
lua_getallocf(internalState, reinterpret_cast<void**>(&instance));
return *instance;
}
int LuaState::ProxyFunc(lua_State* internalState)
{
LuaFunction& func = *static_cast<LuaFunction*>(lua_touserdata(internalState, lua_upvalueindex(1)));
LuaState state = GetState(internalState);
return func(state);
}
}

View File

@@ -19,7 +19,6 @@ namespace Nz
* \param number Optional argument to return the number parsed
* \param endOfRead Optional argument to determine where parsing stopped
*/
bool ParseDecimal(const char* str, unsigned int* number, const char** endOfRead)
{
const char* ptr = str;
@@ -52,7 +51,6 @@ namespace Nz
* \param number Optional argument to return the number parsed
* \param endOfRead Optional argument to determine where parsing stopped
*/
bool ParseHexadecimal(const char* str, unsigned int* number, const char** endOfRead)
{
const char* ptr = str;
@@ -78,8 +76,113 @@ namespace Nz
}
}
/*!
* \ingroup network
* \ingroup network
* \brief Returns the text representation of an error
* \return Text representation of an error
*
* \param resolveError Error enumeration
*/
const char* ErrorToString(Nz::ResolveError resolveError)
{
switch (resolveError)
{
case Nz::ResolveError_NoError:
return "No error";
case Nz::ResolveError_Internal:
return "An internal error occurred";
case Nz::ResolveError_ResourceError:
return "The operating system lacks the resources to proceed";
case Nz::ResolveError_NonRecoverable:
return "A nonrecoverable error occurred";
case Nz::ResolveError_NotFound:
return "No such host is known";
case Nz::ResolveError_NotInitialized:
return "Nazara Network has not been initialized";
case Nz::ResolveError_ProtocolNotSupported:
return "A specified protocol is not supported by the server";
case Nz::ResolveError_TemporaryFailure:
return "A temporary failure occurred, try again";
case Nz::ResolveError_Unknown:
return "An unknown error occurred";
default:
return "Invalid error value";
}
}
/*!
* \ingroup network
* \brief Returns the text representation of an error
* \return Text representation of an error
*
* \param socketError Error enumeration
*/
const char* ErrorToString(Nz::SocketError socketError)
{
switch (socketError)
{
case Nz::SocketError_NoError:
return "No error";
case Nz::SocketError_AddressNotAvailable:
return "The address is already in use";
case Nz::SocketError_ConnectionClosed:
return "The connection has been closed";
case Nz::SocketError_ConnectionRefused:
return "The connection attempt was refused";
case Nz::SocketError_DatagramSize:
return "The datagram size is over the system limit";
case Nz::SocketError_Internal:
return "An internal error occurred";
case Nz::SocketError_Packet:
return "Packet encoding or decoding failed";
case Nz::SocketError_NetworkError:
return "Networking subsystem failed";
case Nz::SocketError_NotInitialized:
return "Network module has not been initialized";
case Nz::SocketError_NotSupported:
return "This operation is not supported";
case Nz::SocketError_ResolveError:
return "The hostname couldn't be resolved";
case Nz::SocketError_ResourceError:
return "The operating system lacks the resources to proceed";
case Nz::SocketError_TimedOut:
return "The operation timed out";
case Nz::SocketError_Unknown:
return "An unknown error occurred";
case Nz::SocketError_UnreachableHost:
return "The host is not reachable";
default:
return "Invalid error value";
}
}
/*!
* \ingroup network
* \brief Parse a textual IPv4 or IPv6 address
* \return true If successful
*
@@ -97,7 +200,6 @@ namespace Nz
* \remark Produces a NazaraAssert if addressPtr is invalid
* \remark Produces a NazaraAssert if result is invalid
*/
bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port, bool* isIPv6, const char** endOfRead)
{
NazaraAssert(addressPtr, "Invalid address string");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
// Copyright (C) 2017 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/ENetPacket.hpp>
#include <Nazara/Core/MemoryPool.hpp>
#include <Nazara/Network/Debug.hpp>
namespace Nz
{
/// Temporary
void ENetPacketRef::Reset(ENetPacket* packet)
{
if (m_packet)
{
if (--m_packet->referenceCount == 0)
m_packet->owner->Delete(m_packet);
}
m_packet = packet;
if (m_packet)
m_packet->referenceCount++;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -23,13 +23,19 @@ namespace Nz
void SocketPollerImpl::Clear()
{
m_activeSockets.clear();
m_readyToReadSockets.clear();
m_readyToWriteSockets.clear();
m_sockets.clear();
}
bool SocketPollerImpl::IsReady(SocketHandle socket) const
bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
{
return m_activeSockets.count(socket) != 0;
return m_readyToReadSockets.count(socket) != 0;
}
bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
{
return m_readyToWriteSockets.count(socket) != 0;
}
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
@@ -37,15 +43,21 @@ namespace Nz
return m_sockets.count(socket) != 0;
}
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
{
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
epoll_event event;
event.events = EPOLLIN;
event.data.fd = socket;
epoll_event entry;
entry.events = 0;
entry.data.fd = socket;
if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &event) != 0)
if (eventFlags & SocketPollEvent_Read)
entry.events |= EPOLLIN;
if (eventFlags & SocketPollEvent_Write)
entry.events |= EPOLLOUT;
if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &entry) != 0)
{
NazaraError("Failed to add socket to epoll structure (errno " + String::Number(errno) + ": " + Error::GetLastSystemError() + ')');
return false;
@@ -60,7 +72,8 @@ namespace Nz
{
NazaraAssert(IsRegistered(socket), "Socket is not registered");
m_activeSockets.erase(socket);
m_readyToReadSockets.erase(socket);
m_readyToWriteSockets.erase(socket);
m_sockets.erase(socket);
if (epoll_ctl(m_handle, EPOLL_CTL_DEL, socket, nullptr) != 0)
@@ -84,21 +97,27 @@ namespace Nz
return 0;
}
m_activeSockets.clear();
m_readyToReadSockets.clear();
m_readyToWriteSockets.clear();
if (activeSockets > 0)
{
int socketCount = activeSockets;
for (int i = 0; i < socketCount; ++i)
{
if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
if (m_events[i].events & (EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR))
{
m_activeSockets.insert(m_events[i].data.fd);
if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
m_readyToReadSockets.insert(m_events[i].data.fd);
if (m_events[i].events & (EPOLLOUT | EPOLLERR))
m_readyToWriteSockets.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) + ')');
NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll without EPOLLIN nor EPOLLOUT flags (events: 0x" + String::Number(m_events[i].events, 16) + ')');
activeSockets--;
}
}

View File

@@ -23,16 +23,18 @@ namespace Nz
void Clear();
bool IsReady(SocketHandle socket) const;
bool IsReadyToRead(SocketHandle socket) const;
bool IsReadyToWrite(SocketHandle socket) const;
bool IsRegistered(SocketHandle socket) const;
bool RegisterSocket(SocketHandle socket);
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
void UnregisterSocket(SocketHandle socket);
int Wait(UInt64 msTimeout, SocketError* error);
private:
std::unordered_set<SocketHandle> m_activeSockets;
std::unordered_set<SocketHandle> m_readyToReadSockets;
std::unordered_set<SocketHandle> m_readyToWriteSockets;
std::unordered_set<SocketHandle> m_sockets;
std::vector<epoll_event> m_events;
int m_handle;

View File

@@ -10,14 +10,20 @@ namespace Nz
{
void SocketPollerImpl::Clear()
{
m_activeSockets.clear();
m_readyToReadSockets.clear();
m_readyToWriteSockets.clear();
m_allSockets.clear();
m_sockets.clear();
}
bool SocketPollerImpl::IsReady(SocketHandle socket) const
bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
{
return m_activeSockets.count(socket) != 0;
return m_readyToReadSockets.count(socket) != 0;
}
bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
{
return m_readyToWriteSockets.count(socket) != 0;
}
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
@@ -25,16 +31,22 @@ namespace Nz
return m_allSockets.count(socket) != 0;
}
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
{
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
PollSocket entry = {
socket,
POLLRDNORM,
0,
0
};
if (eventFlags & SocketPollEvent_Read)
entry.events |= POLLRDNORM;
if (eventFlags & SocketPollEvent_Write)
entry.events |= POLLWRNORM;
m_allSockets[socket] = m_sockets.size();
m_sockets.emplace_back(entry);
@@ -57,10 +69,11 @@ namespace Nz
// 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);
m_readyToReadSockets.erase(socket);
m_readyToWriteSockets.erase(socket);
}
int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
@@ -68,20 +81,25 @@ namespace Nz
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 > 0)
m_readyToReadSockets.clear();
m_readyToWriteSockets.clear();
if (activeSockets > 0U)
{
int socketRemaining = activeSockets;
for (PollSocket& entry : m_sockets)
{
if (entry.revents & POLLRDNORM)
if (entry.revents != 0)
{
m_activeSockets.insert(entry.fd);
if (entry.revents & POLLRDNORM)
m_readyToReadSockets.insert(entry.fd);
if (entry.revents & POLLWRNORM)
m_readyToWriteSockets.insert(entry.fd);
entry.revents = 0;
if (--socketRemaining == 0)
break;
}

View File

@@ -27,13 +27,14 @@ namespace Nz
bool IsReady(SocketHandle socket) const;
bool IsRegistered(SocketHandle socket) const;
bool RegisterSocket(SocketHandle socket);
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
void UnregisterSocket(SocketHandle socket);
int Wait(UInt64 msTimeout, SocketError* error);
private:
std::unordered_set<SocketHandle> m_activeSockets;
std::unordered_set<SocketHandle> m_readyToReadSockets;
std::unordered_set<SocketHandle> m_readyToWriteSockets;
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
std::vector<PollSocket> m_sockets;
};

View File

@@ -57,12 +57,13 @@ namespace Nz
/*!
* \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.
* This function allows you to read the results of the last Wait operation and if a specific socket is ready to read (has incoming data).
*
* A socket in the ready state (with the exception of TcpServer) has incoming data and can be read without blocking.
* A socket in the ready to read 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.
* \remark You must call Wait before using this function in order to refresh the read state.
* \remark A socket must be registered with SocketPollerEvent_Read event flag for its read state to be watched
* \remark A TcpServer socket becomes ready to read when it is ready to accept a new client.
*
* \param socket Reference to the socket to check
*
@@ -70,11 +71,32 @@ namespace Nz
*
* \see Wait
*/
bool SocketPoller::IsReady(const AbstractSocket& socket) const
bool SocketPoller::IsReadyToRead(const AbstractSocket& socket) const
{
NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller");
return m_impl->IsReady(socket.GetNativeHandle());
return m_impl->IsReadyToRead(socket.GetNativeHandle());
}
/*!
* \brief Checks if a specific socket is ready to write data
*
* This function allows you to read the results of the last Wait operation and if a specific socket is ready to write (can be written to without blocking).
*
* \remark You must call Wait before using this function in order to refresh the read state.
* \remark A socket must be registered with SocketPollerEvent_Write event flag for its read state to be watched
*
* \param socket Reference to the socket to check
*
* \return True if the socket is available for writing without blocking, false otherwise
*
* \see Wait
*/
bool SocketPoller::IsReadyToWrite(const AbstractSocket& socket) const
{
NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller");
return m_impl->IsReadyToWrite(socket.GetNativeHandle());
}
/*!
@@ -97,7 +119,7 @@ namespace Nz
/*!
* \brief Register a socket in the SocketPoller
*
* A registered socket is part of the SocketPoller and will be checked by the next Wait operations.
* A registered socket is part of the SocketPoller and will be checked by the next Wait operations according to the event flags passed when registered.
*
* The SocketPoller keeps a reference to the internal handle of registered socket, which should not be freed while it is registered in the SocketPooler.
*
@@ -107,17 +129,18 @@ namespace Nz
* \remark The socket should not be freed while it is registered in the SocketPooler.
*
* \param socket Reference to the socket to register
* \param eventFlags Socket events to watch
*
* \return True if the socket is registered, false otherwise
*
* \see IsRegistered
* \see UnregisterSocket
*/
bool SocketPoller::RegisterSocket(AbstractSocket& socket)
bool SocketPoller::RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags)
{
NazaraAssert(!IsRegistered(socket), "This socket is already registered in this SocketPoller");
return m_impl->RegisterSocket(socket.GetNativeHandle());
return m_impl->RegisterSocket(socket.GetNativeHandle(), eventFlags);
}
/*!
@@ -145,7 +168,7 @@ namespace Nz
* \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.
* To query the ready state of the registered socket, use the IsReadyToRead or IsReadyToWrite functions.
*
* \param msTimeout Maximum time to wait in milliseconds, 0 for infinity
*

View File

@@ -10,29 +10,43 @@ namespace Nz
SocketPollerImpl::SocketPollerImpl()
{
#if !NAZARA_NETWORK_POLL_SUPPORT
FD_ZERO(&m_activeSockets);
FD_ZERO(&m_sockets);
FD_ZERO(&m_readSockets);
FD_ZERO(&m_readyToReadSockets);
FD_ZERO(&m_readyToWriteSockets);
FD_ZERO(&m_writeSockets);
#endif
}
void SocketPollerImpl::Clear()
{
#if NAZARA_NETWORK_POLL_SUPPORT
m_activeSockets.clear();
m_allSockets.clear();
m_readyToReadSockets.clear();
m_readyToWriteSockets.clear();
m_sockets.clear();
#else
FD_ZERO(&m_activeSockets);
FD_ZERO(&m_sockets);
FD_ZERO(&m_readSockets);
FD_ZERO(&m_readyToReadSockets);
FD_ZERO(&m_readyToWriteSockets);
FD_ZERO(&m_writeSockets);
#endif
}
bool SocketPollerImpl::IsReady(SocketHandle socket) const
bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
{
#if NAZARA_NETWORK_POLL_SUPPORT
return m_activeSockets.count(socket) != 0;
return m_readyToReadSockets.count(socket) != 0;
#else
return FD_ISSET(socket, &m_activeSockets) != 0;
return FD_ISSET(socket, &m_readyToReadSockets) != 0;
#endif
}
bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
{
#if NAZARA_NETWORK_POLL_SUPPORT
return m_readyToWriteSockets.count(socket) != 0;
#else
return FD_ISSET(socket, &m_readyToWriteSockets) != 0;
#endif
}
@@ -41,31 +55,45 @@ namespace Nz
#if NAZARA_NETWORK_POLL_SUPPORT
return m_allSockets.count(socket) != 0;
#else
return FD_ISSET(socket, &m_sockets) != 0;
return FD_ISSET(socket, &m_readSockets) != 0 ||
FD_ISSET(socket, &m_writeSockets) != 0;
#endif
}
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
{
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
#if NAZARA_NETWORK_POLL_SUPPORT
PollSocket entry = {
socket,
POLLRDNORM,
0,
0
};
if (eventFlags & SocketPollEvent_Read)
entry.events |= POLLRDNORM;
if (eventFlags & SocketPollEvent_Write)
entry.events |= POLLWRNORM;
m_allSockets[socket] = m_sockets.size();
m_sockets.emplace_back(entry);
#else
if (m_sockets.fd_count > FD_SETSIZE)
for (std::size_t i = 0; i < 2; ++i)
{
NazaraError("Socket count exceeding FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
return false;
}
if ((eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write)) == 0)
continue;
FD_SET(socket, &m_sockets);
fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets;
if (targetSet.fd_count > FD_SETSIZE)
{
NazaraError("Socket count exceeding hard-coded FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
return false;
}
FD_SET(socket, &targetSet);
}
#endif
return true;
@@ -88,13 +116,16 @@ namespace Nz
// 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);
m_readyToReadSockets.erase(socket);
m_readyToWriteSockets.erase(socket);
#else
FD_CLR(socket, &m_activeSockets);
FD_CLR(socket, &m_sockets);
FD_CLR(socket, &m_readSockets);
FD_CLR(socket, &m_readyToReadSockets);
FD_CLR(socket, &m_readyToWriteSockets);
FD_CLR(socket, &m_writeSockets);
#endif
}
@@ -103,35 +134,28 @@ namespace Nz
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
fd_set* readSet = nullptr;
fd_set* writeSet = nullptr;
m_activeSockets = m_sockets;
if (m_readSockets.fd_count > 0)
{
m_readyToReadSockets = m_readSockets;
readSet = &m_readyToReadSockets;
}
if (m_writeSockets.fd_count > 0)
{
m_readyToWriteSockets = m_writeSockets;
readSet = &m_readyToWriteSockets;
}
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
activeSockets = ::select(0xDEADBEEF, readSet, writeSet, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
if (activeSockets == SOCKET_ERROR)
{
if (error)

View File

@@ -25,24 +25,28 @@ namespace Nz
void Clear();
bool IsReady(SocketHandle socket) const;
bool IsReadyToRead(SocketHandle socket) const;
bool IsReadyToWrite(SocketHandle socket) const;
bool IsRegistered(SocketHandle socket) const;
bool RegisterSocket(SocketHandle socket);
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
void UnregisterSocket(SocketHandle socket);
int Wait(UInt64 msTimeout, SocketError* error);
private:
#if NAZARA_NETWORK_POLL_SUPPORT
std::unordered_set<SocketHandle> m_activeSockets;
std::unordered_set<SocketHandle> m_readyToReadSockets;
std::unordered_set<SocketHandle> m_readyToWriteSockets;
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
std::vector<PollSocket> m_sockets;
#else
fd_set m_sockets;
fd_set m_activeSockets;
fd_set m_readSockets;
fd_set m_readyToReadSockets;
fd_set m_readyToWriteSockets;
fd_set m_writeSockets;
#endif
};
}
#endif // NAZARA_SOCKETPOLLERIMPL_HPP
#endif // NAZARA_SOCKETPOLLERIMPL_HPP

View File

@@ -124,8 +124,8 @@ namespace Nz
// Some default settings
data.SetParameter(MaterialData::Blending, true);
data.SetParameter(MaterialData::DepthWrite, true);
data.SetParameter(MaterialData::DstBlend, static_cast<int>(BlendFunc_InvSrcAlpha));
data.SetParameter(MaterialData::SrcBlend, static_cast<int>(BlendFunc_SrcAlpha));
data.SetParameter(MaterialData::DstBlend, static_cast<long long>(BlendFunc_InvSrcAlpha));
data.SetParameter(MaterialData::SrcBlend, static_cast<long long>(BlendFunc_SrcAlpha));
}
it = materialCache.emplace(matName, std::move(data)).first;
@@ -139,7 +139,7 @@ namespace Nz
bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
{
int reservedVertexCount;
long long reservedVertexCount;
if (!parameters.custom.GetIntegerParameter("NativeOBJLoader_VertexCount", &reservedVertexCount))
reservedVertexCount = 100;

View File

@@ -128,7 +128,7 @@ namespace Nz
else
{
Color colorVal;
float fValue;
double dValue;
if (matData.GetColorParameter(MaterialData::AmbientColor, &colorVal))
material->ambient = colorVal;
@@ -139,8 +139,8 @@ namespace Nz
if (matData.GetColorParameter(MaterialData::SpecularColor, &colorVal))
material->specular = colorVal;
if (matData.GetFloatParameter(MaterialData::Shininess, &fValue))
material->shininess = fValue;
if (matData.GetDoubleParameter(MaterialData::Shininess, &dValue))
material->shininess = float(dValue);
if (matData.GetStringParameter(MaterialData::AlphaTexturePath, &strVal))
material->alphaMap = strVal;
@@ -176,7 +176,7 @@ namespace Nz
UInt32 faceIndex = 0;
TriangleIterator triangle(staticMesh);
do
do
{
OBJParser::Face& face = meshes[i].faces[faceIndex];
face.firstVertex = faceIndex * 3;

View File

@@ -1268,6 +1268,102 @@ namespace Nz
}
}
bool PixelFormat::Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst)
{
#if NAZARA_UTILITY_SAFE
if (!IsValid(format))
{
NazaraError("Invalid pixel format");
return false;
}
#endif
auto it = s_flipFunctions[flipping].find(format);
if (it != s_flipFunctions[flipping].end())
it->second(width, height, depth, reinterpret_cast<const UInt8*>(src), reinterpret_cast<UInt8*>(dst));
else
{
// Flipping générique
#if NAZARA_UTILITY_SAFE
if (IsCompressed(format))
{
NazaraError("No function to flip compressed format");
return false;
}
#endif
UInt8 bpp = GetBytesPerPixel(format);
unsigned int lineStride = width*bpp;
switch (flipping)
{
case PixelFlipping_Horizontally:
{
if (src == dst)
{
for (unsigned int z = 0; z < depth; ++z)
{
UInt8* ptr = reinterpret_cast<UInt8*>(dst) + width*height*z;
for (unsigned int y = 0; y < height / 2; ++y)
std::swap_ranges(&ptr[y*lineStride], &ptr[(y + 1)*lineStride - 1], &ptr[(height - y - 1)*lineStride]);
}
}
else
{
for (unsigned int z = 0; z < depth; ++z)
{
const UInt8* srcPtr = reinterpret_cast<const UInt8*>(src);
UInt8* dstPtr = reinterpret_cast<UInt8*>(dst) + (width - 1)*height*depth*bpp;
for (unsigned int y = 0; y < height; ++y)
{
std::memcpy(dstPtr, srcPtr, lineStride);
srcPtr += lineStride;
dstPtr -= lineStride;
}
}
}
break;
}
case PixelFlipping_Vertically:
{
if (src == dst)
{
for (unsigned int z = 0; z < depth; ++z)
{
UInt8* ptr = reinterpret_cast<UInt8*>(dst) + width*height*z;
for (unsigned int y = 0; y < height; ++y)
{
for (unsigned int x = 0; x < width / 2; ++x)
std::swap_ranges(&ptr[x*bpp], &ptr[(x + 1)*bpp], &ptr[(width - x)*bpp]);
ptr += lineStride;
}
}
}
else
{
for (unsigned int z = 0; z < depth; ++z)
{
UInt8* ptr = reinterpret_cast<UInt8*>(dst) + width*height*z;
for (unsigned int y = 0; y < height; ++y)
{
for (unsigned int x = 0; x < width; ++x)
std::memcpy(&ptr[x*bpp], &ptr[(width - x)*bpp], bpp);
ptr += lineStride;
}
}
}
break;
}
}
}
return true;
}
PixelFormatType PixelFormat::IdentifyFormat(const PixelFormatInfo& info)
{
for (unsigned int i = 0; i <= PixelFormatType_Max; ++i)