Merge branch 'master' into add-step-extension

pull/3837/head
Kim Kulling 2021-05-06 14:19:53 +02:00 committed by GitHub
commit bc7551b778
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 96 additions and 128 deletions

View File

@ -42,6 +42,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER #ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
#include "D3MFImporter.h" #include "D3MFImporter.h"
#include "3MFXmlTags.h"
#include "D3MFOpcPackage.h"
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
@ -51,17 +53,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/fast_atof.h>
#include <cassert> #include <cassert>
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "3MFXmlTags.h"
#include "D3MFOpcPackage.h"
#include <assimp/fast_atof.h>
#include <iomanip> #include <iomanip>
#include <string.h>
namespace Assimp { namespace Assimp {
namespace D3MF { namespace D3MF {
@ -163,7 +163,7 @@ public:
} }
XmlNode resNode = node.child(XmlTag::resources); XmlNode resNode = node.child(XmlTag::resources);
for (auto &currentNode : resNode.children()) { for (auto &currentNode : resNode.children()) {
const std::string &currentNodeName = currentNode.name(); const std::string currentNodeName = currentNode.name();
if (currentNodeName == XmlTag::object) { if (currentNodeName == XmlTag::object) {
ReadObject(currentNode); ReadObject(currentNode);
} else if (currentNodeName == XmlTag::basematerials) { } else if (currentNodeName == XmlTag::basematerials) {
@ -173,8 +173,9 @@ public:
} }
} }
for (auto &currentNode : resNode.children()) { XmlNode buildNode = node.child(XmlTag::build);
const std::string &currentNodeName = currentNode.name(); for (auto &currentNode : buildNode.children()) {
const std::string currentNodeName = currentNode.name();
if (currentNodeName == XmlTag::item) { if (currentNodeName == XmlTag::item) {
int objectId = -1; int objectId = -1;
std::string transformationMatrixStr; std::string transformationMatrixStr;
@ -196,7 +197,7 @@ public:
// import the metadata // import the metadata
if (!mMetaData.empty()) { if (!mMetaData.empty()) {
const size_t numMeta(mMetaData.size()); const size_t numMeta = mMetaData.size();
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta)); scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
for (size_t i = 0; i < numMeta; ++i) { for (size_t i = 0; i < numMeta; ++i) {
aiString val(mMetaData[i].value); aiString val(mMetaData[i].value);
@ -211,6 +212,7 @@ public:
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it) { for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it) {
if (it->second->getType() == ResourceType::RT_Object) { if (it->second->getType() == ResourceType::RT_Object) {
Object *obj = static_cast<Object *>(it->second); Object *obj = static_cast<Object *>(it->second);
ai_assert(nullptr != obj);
for (unsigned int i = 0; i < obj->mMeshes.size(); ++i) { for (unsigned int i = 0; i < obj->mMeshes.size(); ++i) {
scene->mMeshes[obj->mMeshIndex[i]] = obj->mMeshes[i]; scene->mMeshes[obj->mMeshIndex[i]] = obj->mMeshes[i];
} }
@ -352,7 +354,8 @@ private:
mMeshCount++; mMeshCount++;
} else if (currentName == D3MF::XmlTag::components) { } else if (currentName == D3MF::XmlTag::components) {
for (XmlNode &currentSubNode : currentNode.children()) { for (XmlNode &currentSubNode : currentNode.children()) {
if (currentSubNode.name() == D3MF::XmlTag::component) { const std::string subNodeName = currentSubNode.name();
if (subNodeName == D3MF::XmlTag::component) {
int objectId = -1; int objectId = -1;
std::string componentTransformStr; std::string componentTransformStr;
aiMatrix4x4 componentTransform; aiMatrix4x4 componentTransform;
@ -360,12 +363,13 @@ private:
componentTransform = parseTransformMatrix(componentTransformStr); componentTransform = parseTransformMatrix(componentTransformStr);
} }
if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId)) if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId)) {
obj->mComponents.push_back({ objectId, componentTransform }); obj->mComponents.push_back({ objectId, componentTransform });
} }
} }
} }
} }
}
mResourcesDictionnary.insert(std::make_pair(id, obj)); mResourcesDictionnary.insert(std::make_pair(id, obj));
} }
@ -374,7 +378,7 @@ private:
aiMesh *mesh = new aiMesh(); aiMesh *mesh = new aiMesh();
for (XmlNode &currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string currentName = currentNode.name();
if (currentName == XmlTag::vertices) { if (currentName == XmlTag::vertices) {
ImportVertices(currentNode, mesh); ImportVertices(currentNode, mesh);
} else if (currentName == XmlTag::triangles) { } else if (currentName == XmlTag::triangles) {
@ -402,8 +406,8 @@ private:
void ImportVertices(XmlNode &node, aiMesh *mesh) { void ImportVertices(XmlNode &node, aiMesh *mesh) {
std::vector<aiVector3D> vertices; std::vector<aiVector3D> vertices;
for (XmlNode &currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string currentName = currentNode.name();
if (currentName == D3MF::XmlTag::vertex) { if (currentName == XmlTag::vertex) {
vertices.push_back(ReadVertex(currentNode)); vertices.push_back(ReadVertex(currentNode));
} }
} }
@ -415,22 +419,22 @@ private:
aiVector3D ReadVertex(XmlNode &node) { aiVector3D ReadVertex(XmlNode &node) {
aiVector3D vertex; aiVector3D vertex;
vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::x).as_string(), nullptr); vertex.x = ai_strtof(node.attribute(XmlTag::x).as_string(), nullptr);
vertex.y = ai_strtof(node.attribute(D3MF::XmlTag::y).as_string(), nullptr); vertex.y = ai_strtof(node.attribute(XmlTag::y).as_string(), nullptr);
vertex.z = ai_strtof(node.attribute(D3MF::XmlTag::z).as_string(), nullptr); vertex.z = ai_strtof(node.attribute(XmlTag::z).as_string(), nullptr);
return vertex; return vertex;
} }
void ImportTriangles(XmlNode &node, aiMesh *mesh) { void ImportTriangles(XmlNode &node, aiMesh *mesh) {
std::vector<aiFace> faces; std::vector<aiFace> faces;
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string currentName = currentNode.name();
if (currentName == D3MF::XmlTag::triangle) { if (currentName == XmlTag::triangle) {
aiFace face = ReadTriangle(currentNode); aiFace face = ReadTriangle(currentNode);
faces.push_back(face); faces.push_back(face);
int pid = 0, p1; int pid = 0, p1 = 0;
bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid); bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1); bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
@ -472,10 +476,11 @@ private:
BaseMaterials *baseMaterials = new BaseMaterials(id); BaseMaterials *baseMaterials = new BaseMaterials(id);
for (XmlNode &currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
if (currentNode.name() == XmlTag::basematerials_base) { const std::string currentName = currentNode.name();
if (currentName == XmlTag::basematerials_base) {
baseMaterials->mMaterialIndex.push_back(mMaterialCount); baseMaterials->mMaterialIndex.push_back(mMaterialCount);
baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id)); baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id));
mMaterialCount++; ++mMaterialCount;
} }
} }
@ -564,6 +569,8 @@ private:
} //namespace D3MF } //namespace D3MF
using namespace D3MF;
static const aiImporterDesc desc = { static const aiImporterDesc desc = {
"3mf Importer", "3mf Importer",
"", "",
@ -597,7 +604,7 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo
if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) { if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
return false; return false;
} }
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); D3MFOpcPackage opcPackage(pIOHandler, filename);
return opcPackage.validate(); return opcPackage.validate();
} }
@ -613,11 +620,11 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
} }
void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) { void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); D3MFOpcPackage opcPackage(pIOHandler, filename);
XmlParser xmlParser; XmlParser xmlParser;
if (xmlParser.parse(opcPackage.RootStream())) { if (xmlParser.parse(opcPackage.RootStream())) {
D3MF::XmlSerializer xmlSerializer(&xmlParser); XmlSerializer xmlSerializer(&xmlParser);
xmlSerializer.ImportXml(pScene); xmlSerializer.ImportXml(pScene);
} }
} }

View File

@ -47,9 +47,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
/// @brief The 3MF-importer class.
class D3MFImporter : public BaseImporter { class D3MFImporter : public BaseImporter {
public: public:
// BaseImporter interface
D3MFImporter(); D3MFImporter();
~D3MFImporter(); ~D3MFImporter();
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const; bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;

View File

@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <map>
#ifdef MDL_HALFLIFE_LOG_WARN_HEADER #ifdef MDL_HALFLIFE_LOG_WARN_HEADER
#undef MDL_HALFLIFE_LOG_WARN_HEADER #undef MDL_HALFLIFE_LOG_WARN_HEADER

View File

@ -65,20 +65,6 @@ using namespace Assimp;
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
BaseImporter::BaseImporter() AI_NO_EXCEPT BaseImporter::BaseImporter() AI_NO_EXCEPT
: m_progress() { : m_progress() {
/**
* Assimp Importer
* unit conversions available
* if you need another measurment unit add it below.
* it's currently defined in assimp that we prefer meters.
*
* NOTE: Initialised here rather than in the header file
* to workaround a VS2013 bug with brace initialisers
* */
importerUnits[ImporterUnits::M] = 1.0;
importerUnits[ImporterUnits::CM] = 0.01;
importerUnits[ImporterUnits::MM] = 0.001;
importerUnits[ImporterUnits::INCHES] = 0.0254;
importerUnits[ImporterUnits::FEET] = 0.3048;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -51,10 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Exceptional.h" #include "Exceptional.h"
#include <assimp/ai_assert.h>
#include <assimp/types.h> #include <assimp/types.h>
#include <assimp/ProgressHandler.hpp> #include <assimp/ProgressHandler.hpp>
#include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include <memory> #include <memory>
@ -179,42 +177,10 @@ public:
/** /**
* Will be called only by scale process when scaling is requested. * Will be called only by scale process when scaling is requested.
*/ */
virtual void SetFileScale(double scale) { void SetFileScale(double scale) {
fileScale = scale; fileScale = scale;
} }
virtual double GetFileScale() const {
return fileScale;
}
enum ImporterUnits {
M,
MM,
CM,
INCHES,
FEET
};
/**
* Assimp Importer
* unit conversions available
* NOTE: Valid options are initialised in the
* constructor in the implementation file to
* work around a VS2013 compiler bug if support
* for that compiler is dropped in the future
* initialisation can be moved back here
* */
std::map<ImporterUnits, double> importerUnits;
virtual void SetApplicationUnits(const ImporterUnits &unit) {
importerScale = importerUnits[unit];
applicationUnits = unit;
}
virtual const ImporterUnits &GetApplicationUnits() {
return applicationUnits;
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called by #Importer::GetExtensionList for each loaded importer. /** Called by #Importer::GetExtensionList for each loaded importer.
* Take the extension list contained in the structure returned by * Take the extension list contained in the structure returned by
@ -223,7 +189,6 @@ public:
void GetExtensionList(std::set<std::string> &extensions); void GetExtensionList(std::set<std::string> &extensions);
protected: protected:
ImporterUnits applicationUnits = ImporterUnits::M;
double importerScale = 1.0; double importerScale = 1.0;
double fileScale = 1.0; double fileScale = 1.0;
@ -420,7 +385,7 @@ public: // static utilities
private: private:
/* Pushes state into importer for the importer scale */ /* Pushes state into importer for the importer scale */
virtual void UpdateImporterScale(Importer *pImp); void UpdateImporterScale(Importer *pImp);
protected: protected:
/// Error description in case there was one. /// Error description in case there was one.

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team Copyright (c) 2006-2021, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -55,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstdlib> #include <cstdlib>
#include <locale> #include <locale>
#include <sstream> #include <sstream>
#include <iomanip>
#ifdef _MSC_VER #ifdef _MSC_VER
#define AI_SIZEFMT "%Iu" #define AI_SIZEFMT "%Iu"
@ -177,7 +177,7 @@ AI_FORCE_INLINE std::string ai_rgba2hex(int r, int g, int b, int a, bool with_he
if (with_head) { if (with_head) {
ss << "#"; ss << "#";
} }
ss << std::hex << (r << 24 | g << 16 | b << 8 | a); ss << std::hex << std::setfill('0') << std::setw(8) << (r << 24 | g << 16 | b << 8 | a);
return ss.str(); return ss.str();
} }
@ -249,4 +249,4 @@ AI_FORCE_INLINE std::string ai_str_toupper(const std::string &in) {
return out; return out;
} }
#endif #endif // INCLUDED_AI_STRINGUTILS_H

View File

@ -43,8 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_IRRXML_WRAPPER #define INCLUDED_AI_IRRXML_WRAPPER
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/ai_assert.h>
#include "BaseImporter.h" #include "BaseImporter.h"
#include "IOStream.hpp" #include "IOStream.hpp"
#include <pugixml.hpp> #include <pugixml.hpp>
#include <vector> #include <vector>

View File

@ -42,22 +42,12 @@ void ModelLoader::Draw(ID3D11DeviceContext * devcon) {
} }
} }
std::string textype;
Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) { Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) {
// Data to fill // Data to fill
std::vector<VERTEX> vertices; std::vector<VERTEX> vertices;
std::vector<UINT> indices; std::vector<UINT> indices;
std::vector<Texture> textures; std::vector<Texture> textures;
if (mesh->mMaterialIndex >= 0) {
aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
if (textype.empty()) {
textype = determineTextureType(scene, mat);
}
}
// Walk through each of the mesh's vertices // Walk through each of the mesh's vertices
for (UINT i = 0; i < mesh->mNumVertices; i++) { for (UINT i = 0; i < mesh->mNumVertices; i++) {
VERTEX vertex; VERTEX vertex;
@ -108,9 +98,10 @@ std::vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextu
if (!skip) { // If texture hasn't been loaded already, load it if (!skip) { // If texture hasn't been loaded already, load it
HRESULT hr; HRESULT hr;
Texture texture; Texture texture;
if (textype == "embedded compressed texture") {
int textureindex = getTextureIndex(&str); const aiTexture* embeddedTexture = scene->GetEmbeddedTexture(str.C_Str());
texture.texture = getTextureFromModel(scene, textureindex); if (embeddedTexture != nullptr) {
texture.texture = loadEmbeddedTexture(embeddedTexture);
} else { } else {
std::string filename = std::string(str.C_Str()); std::string filename = std::string(str.C_Str());
filename = directory_ + '/' + filename; filename = directory_ + '/' + filename;
@ -148,38 +139,46 @@ void ModelLoader::processNode(aiNode * node, const aiScene * scene) {
} }
} }
std::string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat) { ID3D11ShaderResourceView * ModelLoader::loadEmbeddedTexture(const aiTexture* embeddedTexture) {
aiString textypeStr;
mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr);
std::string textypeteststr = textypeStr.C_Str();
if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5") {
if (scene->mTextures[0]->mHeight == 0) {
return "embedded compressed texture";
} else {
return "embedded non-compressed texture";
}
}
if (textypeteststr.find('.') != std::string::npos) {
return "textures are on disk";
}
return ".";
}
int ModelLoader::getTextureIndex(aiString * str) {
std::string tistr;
tistr = str->C_Str();
tistr = tistr.substr(1);
return stoi(tistr);
}
ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex) {
HRESULT hr; HRESULT hr;
ID3D11ShaderResourceView *texture; ID3D11ShaderResourceView *texture = nullptr;
int* size = reinterpret_cast<int*>(&scene->mTextures[textureindex]->mWidth); if (embeddedTexture->mHeight != 0) {
// Load an uncompressed ARGB8888 embedded texture
D3D11_TEXTURE2D_DESC desc;
desc.Width = embeddedTexture->mWidth;
desc.Height = embeddedTexture->mHeight;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
hr = CreateWICTextureFromMemory(dev_, devcon_, reinterpret_cast<unsigned char*>(scene->mTextures[textureindex]->pcData), *size, nullptr, &texture); D3D11_SUBRESOURCE_DATA subresourceData;
subresourceData.pSysMem = embeddedTexture->pcData;
subresourceData.SysMemPitch = embeddedTexture->mWidth * 4;
subresourceData.SysMemSlicePitch = embeddedTexture->mWidth * embeddedTexture->mHeight * 4;
ID3D11Texture2D *texture2D = nullptr;
hr = dev_->CreateTexture2D(&desc, &subresourceData, &texture2D);
if (FAILED(hr))
MessageBox(hwnd_, "CreateTexture2D failed!", "Error!", MB_ICONERROR | MB_OK);
hr = dev_->CreateShaderResourceView(texture2D, nullptr, &texture);
if (FAILED(hr))
MessageBox(hwnd_, "CreateShaderResourceView failed!", "Error!", MB_ICONERROR | MB_OK);
return texture;
}
// mHeight is 0, so try to load a compressed texture of mWidth bytes
const size_t size = embeddedTexture->mWidth;
hr = CreateWICTextureFromMemory(dev_, devcon_, reinterpret_cast<const unsigned char*>(embeddedTexture->pcData), size, nullptr, &texture);
if (FAILED(hr)) if (FAILED(hr))
MessageBox(hwnd_, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK); MessageBox(hwnd_, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK);

View File

@ -35,9 +35,7 @@ private:
void processNode(aiNode* node, const aiScene* scene); void processNode(aiNode* node, const aiScene* scene);
Mesh processMesh(aiMesh* mesh, const aiScene* scene); Mesh processMesh(aiMesh* mesh, const aiScene* scene);
std::vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName, const aiScene* scene); std::vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName, const aiScene* scene);
std::string determineTextureType(const aiScene* scene, aiMaterial* mat); ID3D11ShaderResourceView* loadEmbeddedTexture(const aiTexture* embeddedTexture);
int getTextureIndex(aiString* str);
ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex);
}; };
#endif // !MODEL_LOADER_H #endif // !MODEL_LOADER_H

BIN
test/test.3mf 100644

Binary file not shown.

View File

@ -42,9 +42,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
class utStringUtils : public ::testing::Test { class utStringUtils : public ::testing::Test {
// empty
}; };
TEST_F( utStringUtils, to_string_Test ) { TEST_F(utStringUtils, to_string_Test ) {
std::string res = ai_to_string( 1 ); std::string res = ai_to_string( 1 );
EXPECT_EQ( res, "1" ); EXPECT_EQ( res, "1" );
@ -52,7 +53,7 @@ TEST_F( utStringUtils, to_string_Test ) {
EXPECT_EQ( res, "1" ); EXPECT_EQ( res, "1" );
} }
TEST_F( utStringUtils, ai_strtofTest ) { TEST_F(utStringUtils, ai_strtofTest ) {
float res = ai_strtof( nullptr, nullptr ); float res = ai_strtof( nullptr, nullptr );
EXPECT_FLOAT_EQ( res, 0.0f ); EXPECT_FLOAT_EQ( res, 0.0f );
@ -66,3 +67,11 @@ TEST_F( utStringUtils, ai_strtofTest ) {
res = ai_strtof( begin, end ); res = ai_strtof( begin, end );
EXPECT_FLOAT_EQ( res, 200.0f ); EXPECT_FLOAT_EQ( res, 200.0f );
} }
TEST_F(utStringUtils, ai_rgba2hexTest) {
std::string result;
result = ai_rgba2hex(255, 255, 255, 255, true);
EXPECT_EQ(result, "#ffffffff");
result = ai_rgba2hex(0, 0, 0, 0, false);
EXPECT_EQ(result, "00000000");
}