2626#include < fstream>
2727#include < unordered_map>
2828#include < unordered_set>
29+ #include < vector>
30+
31+ #define STB_IMAGE_WRITE_IMPLEMENTATION
32+ #include < GLFW/deps/stb_image_write.h>
2933
3034namespace Lux
3135{
@@ -70,6 +74,78 @@ namespace Lux
7074 return !texturePath.empty () && texturePath[0 ] == ' *' ;
7175 }
7276
77+ static std::string ToLower (std::string value)
78+ {
79+ std::transform (value.begin (), value.end (), value.begin (), [](unsigned char c)
80+ {
81+ return (char )std::tolower (c);
82+ });
83+ return value;
84+ }
85+
86+ static std::string GetEmbeddedTextureExtension (const aiTexture* texture)
87+ {
88+ if (!texture)
89+ return " .png" ;
90+
91+ std::string hint = ToLower (texture->achFormatHint );
92+ if (hint == " jpeg" )
93+ hint = " jpg" ;
94+
95+ if (hint == " png" || hint == " jpg" || hint == " bmp" || hint == " tga" )
96+ return " ." + hint;
97+
98+ return " .png" ;
99+ }
100+
101+ static std::filesystem::path GetImportedTexturePath (const std::filesystem::path& meshPath, const std::string& textureName, const std::string& extension)
102+ {
103+ Ref<EditorAssetManager> editorAssetManager = Project::GetEditorAssetManager ();
104+ if (!editorAssetManager)
105+ return {};
106+
107+ std::filesystem::path meshRelativePath = editorAssetManager->GetRelativePath (meshPath).lexically_normal ();
108+ std::filesystem::path textureRelativeDirectory;
109+ if (!meshRelativePath.empty () && !meshRelativePath.is_absolute ())
110+ textureRelativeDirectory = meshRelativePath.parent_path () / " Textures" ;
111+ else
112+ textureRelativeDirectory = std::filesystem::path (" Textures" ) / SanitizeAssetFilename (meshPath.stem ().string ());
113+
114+ const std::string fileName = SanitizeAssetFilename (meshPath.stem ().string () + " _" + textureName) + extension;
115+ return (textureRelativeDirectory / fileName).lexically_normal ();
116+ }
117+
118+ static bool WriteEmbeddedTextureToFile (const aiTexture* texture, const std::filesystem::path& filesystemPath)
119+ {
120+ if (!texture)
121+ return false ;
122+
123+ std::error_code ec;
124+ std::filesystem::create_directories (filesystemPath.parent_path (), ec);
125+
126+ if (texture->mHeight == 0 )
127+ {
128+ std::ofstream stream (filesystemPath, std::ios::binary);
129+ if (!stream.is_open ())
130+ return false ;
131+
132+ stream.write (reinterpret_cast <const char *>(texture->pcData ), texture->mWidth );
133+ return stream.good ();
134+ }
135+
136+ std::vector<uint8_t > rgba (texture->mWidth * texture->mHeight * 4 );
137+ for (uint32_t i = 0 ; i < texture->mWidth * texture->mHeight ; i++)
138+ {
139+ const aiTexel& texel = texture->pcData [i];
140+ rgba[i * 4 + 0 ] = texel.r ;
141+ rgba[i * 4 + 1 ] = texel.g ;
142+ rgba[i * 4 + 2 ] = texel.b ;
143+ rgba[i * 4 + 3 ] = texel.a ;
144+ }
145+
146+ return stbi_write_png (filesystemPath.string ().c_str (), texture->mWidth , texture->mHeight , 4 , rgba.data (), texture->mWidth * 4 ) != 0 ;
147+ }
148+
73149 static std::filesystem::path ResolveTexturePath (const std::filesystem::path& meshPath, const aiString& assimpPath)
74150 {
75151 std::filesystem::path texturePath = std::filesystem::path (assimpPath.C_Str ());
@@ -117,42 +193,85 @@ namespace Lux
117193 paths.emplace_back (resolvedPath);
118194 }
119195
120- static AssetHandle ImportTextureReference (const std::filesystem::path& meshPath, const aiScene* scene, aiMaterial* material, const std::initializer_list<aiTextureType>& textureTypes , std::unordered_map<std::string, AssetHandle>& textureCache)
196+ static AssetHandle ImportTexturePathReference (const std::filesystem::path& meshPath, const aiScene* scene, const aiString& texturePath , std::unordered_map<std::string, AssetHandle>& textureCache)
121197 {
122198 Ref<EditorAssetManager> editorAssetManager = Project::GetEditorAssetManager ();
123- if (!editorAssetManager || !material )
199+ if (!editorAssetManager)
124200 return 0 ;
125201
126- for (aiTextureType textureType : textureTypes)
127- {
128- if (material->GetTextureCount (textureType) == 0 )
129- continue ;
202+ const std::string rawPath = texturePath.C_Str ();
203+ if (rawPath.empty ())
204+ return 0 ;
130205
131- aiString texturePath;
132- if (material->GetTexture (textureType, 0 , &texturePath) != AI_SUCCESS )
133- continue ;
206+ if (const aiTexture* embeddedTexture = scene ? scene->GetEmbeddedTexture (rawPath.c_str ()) : nullptr )
207+ {
208+ const std::string cacheKey = meshPath.lexically_normal ().generic_string () + " ::embedded::" + rawPath;
209+ if (auto it = textureCache.find (cacheKey); it != textureCache.end ())
210+ return it->second ;
134211
135- const std::string rawPath = texturePath.C_Str ();
136- if (rawPath.empty () || IsEmbeddedTextureReference (rawPath) || (scene && scene->GetEmbeddedTexture (rawPath.c_str ())))
137- continue ;
212+ const std::string extension = GetEmbeddedTextureExtension (embeddedTexture);
213+ const std::filesystem::path textureRelativePath = GetImportedTexturePath (meshPath, rawPath, extension);
214+ if (textureRelativePath.empty ())
215+ return 0 ;
138216
139- std::filesystem::path resolvedPath = FindTexturePath (meshPath, texturePath) ;
140- if (resolvedPath. empty ( ))
217+ const std::filesystem::path textureFilesystemPath = Project::GetActiveAssetDirectory () / textureRelativePath ;
218+ if (! std::filesystem::exists (textureFilesystemPath) && ! WriteEmbeddedTextureToFile (embeddedTexture, textureFilesystemPath ))
141219 {
142- LUX_CORE_WARN (" AssimpMeshImporter: texture '{}' referenced by '{}' was not found " , rawPath, meshPath.filename ().string ());
143- continue ;
220+ LUX_CORE_WARN (" AssimpMeshImporter: failed to extract embedded texture '{}' from '{}'" , rawPath, meshPath.filename ().string ());
221+ return 0 ;
144222 }
145223
146- const std::string cacheKey = resolvedPath.lexically_normal ().generic_string ();
147- if (auto it = textureCache.find (cacheKey); it != textureCache.end ())
148- return it->second ;
149-
150- AssetHandle textureHandle = editorAssetManager->ImportAsset (resolvedPath);
224+ AssetHandle textureHandle = editorAssetManager->ImportAsset (textureRelativePath);
151225 if (textureHandle && AssetManager::GetAssetType (textureHandle) == AssetType::Texture)
152226 {
153227 textureCache[cacheKey] = textureHandle;
154228 return textureHandle;
155229 }
230+
231+ return 0 ;
232+ }
233+
234+ if (IsEmbeddedTextureReference (rawPath))
235+ return 0 ;
236+
237+ std::filesystem::path resolvedPath = FindTexturePath (meshPath, texturePath);
238+ if (resolvedPath.empty ())
239+ {
240+ LUX_CORE_WARN (" AssimpMeshImporter: texture '{}' referenced by '{}' was not found" , rawPath, meshPath.filename ().string ());
241+ return 0 ;
242+ }
243+
244+ const std::string cacheKey = resolvedPath.lexically_normal ().generic_string ();
245+ if (auto it = textureCache.find (cacheKey); it != textureCache.end ())
246+ return it->second ;
247+
248+ AssetHandle textureHandle = editorAssetManager->ImportAsset (resolvedPath);
249+ if (textureHandle && AssetManager::GetAssetType (textureHandle) == AssetType::Texture)
250+ {
251+ textureCache[cacheKey] = textureHandle;
252+ return textureHandle;
253+ }
254+
255+ return 0 ;
256+ }
257+
258+ static AssetHandle ImportTextureReference (const std::filesystem::path& meshPath, const aiScene* scene, aiMaterial* material, const std::initializer_list<aiTextureType>& textureTypes, std::unordered_map<std::string, AssetHandle>& textureCache)
259+ {
260+ if (!material)
261+ return 0 ;
262+
263+ for (aiTextureType textureType : textureTypes)
264+ {
265+ if (material->GetTextureCount (textureType) == 0 )
266+ continue ;
267+
268+ aiString texturePath;
269+ if (material->GetTexture (textureType, 0 , &texturePath) != AI_SUCCESS )
270+ continue ;
271+
272+ AssetHandle textureHandle = ImportTexturePathReference (meshPath, scene, texturePath, textureCache);
273+ if (textureHandle)
274+ return textureHandle;
156275 }
157276
158277 return 0 ;
@@ -271,7 +390,7 @@ namespace Lux
271390 if (!scene)
272391 return texturePaths;
273392
274- constexpr std::array<aiTextureType, 9 > textureTypes = {
393+ constexpr std::array<aiTextureType, 10 > textureTypes = {
275394 aiTextureType_BASE_COLOR,
276395 aiTextureType_DIFFUSE,
277396 aiTextureType_NORMAL_CAMERA,
@@ -280,7 +399,8 @@ namespace Lux
280399 aiTextureType_METALNESS,
281400 aiTextureType_DIFFUSE_ROUGHNESS,
282401 aiTextureType_SHININESS,
283- aiTextureType_EMISSIVE
402+ aiTextureType_EMISSIVE,
403+ aiTextureType_UNKNOWN
284404 };
285405
286406 for (uint32_t materialIndex = 0 ; materialIndex < scene->mNumMaterials ; materialIndex++)
0 commit comments