Files
XCEngine/engine/third_party/physx/snippets/snippetvehiclecommon/serialization/SerializationCommon.cpp

363 lines
12 KiB
C++

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#include "SerializationCommon.h"
#include <fstream>
#include <sstream>
namespace snippetvehicle
{
bool openDocument(const char* directory, const char* filename,
rapidjson::Document& document)
{
// Check the json file exists.
std::string fileWithPath(directory);
fileWithPath.push_back('/');
fileWithPath.append(filename);
std::ifstream inputFile(fileWithPath);
if (!inputFile.is_open())
{
printf("Opening file \"%s\" failed.\n", fileWithPath.c_str());
return false;
}
// Check the json file can be loaded by rapidjson.
// Failures might be missing commas or braces.
std::string inputData{ std::istreambuf_iterator<char>(inputFile), std::istreambuf_iterator<char>() };
document.Parse(inputData.c_str());
inputFile.close();
if (!document.IsObject())
{
printf("Parsing file \"%s\" failed.\n", fileWithPath.c_str());
return false;
}
return true;
}
bool readCommandResponseParams
(const rapidjson::Value& value, const PxVehicleAxleDescription& axleDesc,
PxVehicleCommandResponseParams& responseParams)
{
if (!value.HasMember("MaxResponse"))
return false;
responseParams.maxResponse = static_cast<PxReal>(value["MaxResponse"].GetDouble());
if (!value.HasMember("WheelResponseMultipliers"))
return false;
const rapidjson::Value& responseMultipliers = value["WheelResponseMultipliers"];
if (responseMultipliers.Size() < axleDesc.nbWheels)
return false;
if (responseMultipliers.Size() > PxVehicleLimits::eMAX_NB_WHEELS)
return false;
for (PxU32 i = 0; i < responseMultipliers.Size(); i++)
{
responseParams.wheelResponseMultipliers[i] = static_cast<PxReal>(responseMultipliers[i].GetDouble());
}
//Nonlinear response is not mandatory.
responseParams.nonlinearResponse.clear();
if(!value.HasMember("NonLinearResponse"))
return true;
const rapidjson::Value& nonlinearResponse = value["NonLinearResponse"];
const int nbCommandValues = nonlinearResponse.Size();
for (int i = 0; i < nbCommandValues; i++)
{
PxVehicleCommandValueResponseTable commandValueResponse;
//Read the throttle value and set it.
const rapidjson::Value& commandAndResponse = nonlinearResponse[i];
if (!commandAndResponse.HasMember("Throttle"))
return false;
const PxReal commandValue = static_cast<PxReal>(commandAndResponse["Throttle"].GetDouble());
commandValueResponse.commandValue = commandValue;
//Read the array of (speed, torque) entries.
if (!commandAndResponse.HasMember("ResponseCurve"))
return false;
const rapidjson::Value& torqueCurve = commandAndResponse["ResponseCurve"];
const PxU32 nbItems = torqueCurve.Size();
for (PxU32 j = 0; j < nbItems; j++)
{
const rapidjson::Value& torqueCurveItem = torqueCurve[j];
if (torqueCurveItem.Size() != 2)
return false;
const PxReal speed = static_cast<PxReal>(torqueCurveItem[0].GetDouble());
const PxReal normalisedResponse = static_cast<PxReal>(torqueCurveItem[1].GetDouble());
commandValueResponse.speedResponses.addPair(speed, normalisedResponse);
}
responseParams.nonlinearResponse.addResponse(commandValueResponse);
}
return true;
}
bool writeCommandResponseParams
(const PxVehicleCommandResponseParams& responseParams, const PxVehicleAxleDescription& axleDesc,
rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
writer.Key("MaxResponse");
writer.Double(static_cast<double>(responseParams.maxResponse));
writer.Key("WheelResponseMultipliers");
writer.StartArray();
for(PxU32 i = 0; i < axleDesc.nbWheels; i++)
{
const PxU32 wheelId = axleDesc.wheelIdsInAxleOrder[i];
writer.Double(static_cast<double>(responseParams.wheelResponseMultipliers[wheelId]));
}
writer.EndArray();
writer.Key("ResponseCurve");
writer.StartArray();
for (PxU32 i = 0; i < responseParams.nonlinearResponse.nbCommandValues; i++)
{
writer.Key("Throttle");
writer.Double(static_cast<double>(responseParams.nonlinearResponse.commandValues[i]));
writer.Key("ResponseCurve");
writer.StartArray();
const PxReal* speeds = responseParams.nonlinearResponse.speedResponses + responseParams.nonlinearResponse.speedResponsesPerCommandValue[i];
const PxReal* responses = speeds + responseParams.nonlinearResponse.nbSpeedResponsesPerCommandValue[i];
for (PxU32 j = 0; j < responseParams.nonlinearResponse.nbSpeedResponsesPerCommandValue[i]; j++)
{
writer.StartArray();
writer.Double(static_cast<double>(speeds[j]));
writer.Double(static_cast<double>(responses[j]));
writer.EndArray();
}
writer.EndArray();
}
writer.EndArray();
return true;
}
void writeCommandResponseParams
(const PxVehicleAxleDescription& axleDesc, const PxVehicleCommandResponseParams& throttleResponseParams,
rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
writer.StartObject();
writer.Key("MaxResponse");
writer.Double(static_cast<double>(throttleResponseParams.maxResponse));
writer.Key("WheelResponseMultipliers");
writer.StartArray();
for(PxU32 i = 0; i < axleDesc.nbWheels; i++)
{
const PxU32 wheelId = axleDesc.wheelIdsInAxleOrder[i];
writer.Double(static_cast<double>(throttleResponseParams.wheelResponseMultipliers[wheelId]));
}
writer.EndArray();
writer.EndObject();
}
bool readVec3(const rapidjson::Value& values, PxVec3& r)
{
if (values.Size() != 3)
return false;
r.x = static_cast<PxReal>(values[0].GetDouble());
r.y = static_cast<PxReal>(values[1].GetDouble());
r.z = static_cast<PxReal>(values[2].GetDouble());
return true;
}
bool writeVec3(const PxVec3& r, rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
writer.StartArray();
writer.Double(static_cast<double>(r.x));
writer.Double(static_cast<double>(r.y));
writer.Double(static_cast<double>(r.z));
writer.EndArray();
return true;
}
bool readQuat(const rapidjson::Value& values, PxQuat& r)
{
if (values.Size() != 4)
return false;
r.x = static_cast<PxReal>(values[0].GetDouble());
r.y = static_cast<PxReal>(values[1].GetDouble());
r.z = static_cast<PxReal>(values[2].GetDouble());
r.w = static_cast<PxReal>(values[3].GetDouble());
return true;
}
bool writeQuat(const PxQuat& r, rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
writer.StartArray();
writer.Double(static_cast<double>(r.x));
writer.Double(static_cast<double>(r.y));
writer.Double(static_cast<double>(r.z));
writer.Double(static_cast<double>(r.w));
writer.EndArray();
return true;
}
bool readTransform(const rapidjson::Value& values, PxTransform& r)
{
if (!values.HasMember("Pos"))
return false;
if (!values.HasMember("Quat"))
return false;
if (!readVec3(values["Pos"], r.p))
return false;
if (!readQuat(values["Quat"], r.q))
return false;
return true;
}
bool writeTransform(const PxTransform& r, rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
writer.StartObject();
writer.Key("Pos");
writeVec3(r.p, writer);
writer.Key("Quat");
writeQuat(r.q, writer);
writer.EndObject();
return true;
}
template<const PxU32 N>
bool readFloatLookupTableN(const rapidjson::Value& values, PxVehicleFixedSizeLookupTable<PxReal, N>& lookupTable)
{
lookupTable.clear();
if (values.Size() > N)
return false;
for (PxU32 i = 0; i < values.Size(); i++)
{
const rapidjson::Value& element = values[i];
if (element.Size() != 2)
return false;
const PxReal x = static_cast<PxReal>(values[i][0].GetDouble());
const PxReal y = static_cast<PxReal>(values[i][1].GetDouble());
lookupTable.addPair(x, y);
}
return true;
}
bool readFloatLookupTable
(const rapidjson::Value& values, PxVehicleFixedSizeLookupTable<PxReal, 3>& lookupTable)
{
return readFloatLookupTableN<3>(values, lookupTable);
}
bool readFloatLookupTable
(const rapidjson::Value& values, PxVehicleFixedSizeLookupTable<PxReal, PxVehicleEngineParams::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES>& lookupTable)
{
return readFloatLookupTableN<PxVehicleEngineParams::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES>(values, lookupTable);
}
template<const PxU32 N>
bool writeFloatLookupTable(const PxVehicleFixedSizeLookupTable<PxReal, N>& lookupTable, rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
writer.StartArray();
for (PxU32 i = 0; i < lookupTable.nbDataPairs; i++)
{
writer.StartArray();
writer.Double(static_cast<double>(lookupTable.xVals[i]));
writer.Double(static_cast<double>(lookupTable.yVals[i]));
writer.EndArray();
}
writer.EndArray();
return true;
}
bool writeFloatLookupTable(const PxVehicleFixedSizeLookupTable<PxReal, 3>& lookupTable, rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
return writeFloatLookupTable<3>(lookupTable, writer);
}
bool writeFloatLookupTable(const PxVehicleFixedSizeLookupTable<PxReal, PxVehicleEngineParams::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES>& lookupTable, rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
return writeFloatLookupTable<PxVehicleEngineParams::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES>(lookupTable, writer);
}
bool readVec3LookupTable(const rapidjson::Value& values, PxVehicleFixedSizeLookupTable<PxVec3, 3>& lookupTable)
{
lookupTable.clear();
if (values.Size() > 3)
return false;
for (PxU32 i = 0; i < values.Size(); i++)
{
const rapidjson::Value& element = values[i];
if (element.Size() != 4)
return false;
const PxReal x = static_cast<PxReal>(values[i][0].GetDouble());
const PxVec3 y(static_cast<PxReal>(
values[i][1].GetDouble()), static_cast<PxReal>(values[i][2].GetDouble()), static_cast<PxReal>(values[i][3].GetDouble()));
lookupTable.addPair(x, y);
}
return true;
}
bool writeVec3LookupTable(const PxVehicleFixedSizeLookupTable<PxVec3, 3>& lookupTable, rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer)
{
writer.StartArray();
for (PxU32 i = 0; i < lookupTable.nbDataPairs; i++)
{
writer.StartArray();
writer.Double(static_cast<double>(lookupTable.xVals[i]));
writer.Double(static_cast<double>(lookupTable.yVals[i].x));
writer.Double(static_cast<double>(lookupTable.yVals[i].y));
writer.Double(static_cast<double>(lookupTable.yVals[i].z));
writer.EndArray();
}
writer.EndArray();
return true;
}
}//namespace snippetvehicle