Преглед на файлове

Implemented ModelComponent configuration in inspector in EditorWindow
Reimplemented (and split into different methods) model, mesh and texture loading in ModelComponent, so data can be changed without reloading the whole component
Added received data handling and checks whether anything needs to be loaded in ModelComponent
Added checking for ModelComponents that have new data pending for loading, in RendererScene
Added mesh name loading from a model file in ModelLoader
Added a flag telling whether a texture was loaded from file or created on the fly, in TextureLoader
Added a way to load multiple models in a single ModelComponent instance
Added models, meshes, textures and their parameters to inspector in EditorWindow
Added a popup window for setting a model or a texture to an already loaded one in EditorWindow
Added a file browser for model and texture files in EditorWindow
Added currently loaded asset (textures and models) iteration in EditorWindow
Added a way to pass emissive color multiplier to geometry shader in RendererFrontend, GraphicsDataSets, ShaderUniforms, UniformData, GeometryPass shader
Added more ErrorCodes and error strings
Added more Config variables
Removed unused code from LightComponent
Fixed a bug of Confirm Overwrite flag being left on in the File Browser Dialog after saving a scene to a file in EditowWindow

Paul A преди 2 години
родител
ревизия
2f5c135fe7

+ 5 - 3
Praxis3D/Data/Shaders/geometryPass.frag

@@ -365,18 +365,20 @@ void main(void)
 	// Get roughness and metalness values, and emissive color
 	float roughness = getRoughness(newCoords);
 	float metalness = getMetalness(newCoords);
-	//vec4 emissiveColor = pow(texture(emissiveTexture, newCoords), vec4(gamma, gamma, gamma, 1.0));
 	vec4 emissiveColor = texture(emissiveTexture, newCoords).rgba;
+	//vec4 emissiveColor = pow(texture(emissiveTexture, newCoords), vec4(gamma, gamma, gamma, 1.0));
 	
+	// Use emissive alpha channel as an intensity multiplier
+	emissiveColor *= emissiveMultiplier;
 	// Apply emissive color only if it's above the threshold
 	if(emissiveColor.a > emissiveThreshold)
 	{
 		// Use emissive alpha channel as an intensity multiplier
-		emissiveColor *= emissiveColor.a * emissiveMultiplier;
+		//emissiveColor *= emissiveColor.a * emissiveMultiplier;
 	}
 	else
 	{
-		emissiveColor = vec4(0.0);
+		//emissiveColor = vec4(0.0);
 	}
 	
 	// Write diffuse color to the diffuse buffer

+ 5 - 0
Praxis3D/Data/error-strings-eng.data

@@ -6,6 +6,10 @@
 		"Failure"														: "Failed",
 		"Initialize_success"								: "Has been initialized",
 		"Initialize_failure"								: "Failed to initialized",
+		"Load_success"											: "Has been loaded",
+		"Load_failure"											: "Failed to load",
+		"Load_to_memory_success"						: "Has been loaded to memory",
+		"Load_to_memory_failure"						: "Failed to load to memory",
 		"File_not_found"										: "File missing",
 		"Filename_empty"										: "Filename is empty",
 		"Audio_invalid_bus_type"						: "Trying to assign an invalid audio bus type",
@@ -37,6 +41,7 @@
 		"Shader_link_failed"								: "Shader linking has failed",
 		"Shader_loading_failed"							: "Shader has failed to load",
 		"GameObjects_missing"								: "GameObjects missing from the map file",
+		"Number_of_meshes_missmatch"				: "Number of meshes is bigger than a mesh property array",
 		"Texture_not_found"									: "Texture was not found",
 		"Texture_empty"											: "Texture data was not found",
 		"Invalid_num_vid_displays"					: "Invalid number of video displays",

+ 5 - 2
Praxis3D/Source/Config.cpp

@@ -199,6 +199,7 @@ void Config::init()
 	AddVariablePredef(m_GUIVar, gui_render);
 	AddVariablePredef(m_GUIVar, gui_dark_style);
 	AddVariablePredef(m_GUIVar, gui_sequence_array_reserve_size);
+	AddVariablePredef(m_GUIVar, editor_asset_selection_button_size_multiplier);
 	AddVariablePredef(m_GUIVar, editor_float_slider_speed); 
 	AddVariablePredef(m_GUIVar, editor_lua_variables_max_height);
 	AddVariablePredef(m_GUIVar, editor_play_button_size);
@@ -208,10 +209,12 @@ void Config::init()
 	AddVariablePredef(m_GUIVar, gui_file_dialog_dir_color_G);
 	AddVariablePredef(m_GUIVar, gui_file_dialog_dir_color_B); 
 	AddVariablePredef(m_GUIVar, editor_button_add_texture);
-	AddVariablePredef(m_GUIVar, editor_button_delete_entry_texture);
+	AddVariablePredef(m_GUIVar, editor_button_add_list_texture);
+	AddVariablePredef(m_GUIVar, editor_button_delete_entry_texture); 
 	AddVariablePredef(m_GUIVar, editor_button_gui_sequence_texture);
 	AddVariablePredef(m_GUIVar, editor_button_open_file_texture);
-	AddVariablePredef(m_GUIVar, editor_button_pause_texture);
+	AddVariablePredef(m_GUIVar, editor_button_open_asset_list_texture);
+	AddVariablePredef(m_GUIVar, editor_button_pause_texture); 
 	AddVariablePredef(m_GUIVar, editor_button_play_texture);
 	AddVariablePredef(m_GUIVar, editor_button_reload_texture);
 	AddVariablePredef(m_GUIVar, editor_button_restart_texture);

+ 9 - 1
Praxis3D/Source/Config.h

@@ -33,6 +33,7 @@ enum DataType : uint32_t
 	DataType_RenderToTextureResolution,
 	DataType_Texture2D,
 	DataType_Texture3D,
+	DataType_ModelsProperties,
 	// GUI
 	DataType_EnableGUISequence,
 	DataType_EditorWindow,
@@ -349,6 +350,7 @@ namespace Properties
 	Code(Direction,) \
 	Code(DirectionalLight,) \
 	Code(Emissive,) \
+	Code(EmissiveIntensity,) \
 	Code(EnvironmentMapDynamic,) \
 	Code(EnvironmentMapObject,) \
 	Code(FragmentShader,) \
@@ -842,7 +844,7 @@ public:
 			bloom_knee = 0.1f;
 			bloom_threshold = 1.5f;
 			bloom_dirt_intensity = 1.0f;
-			emissive_multiplier = 10.0f;
+			emissive_multiplier = 0.0f;
 			emissive_threshold = 0.01f;
 			eye_adaption_rate = 0.25f;
 			eye_adaption_intended_brightness = 0.5f;
@@ -943,6 +945,7 @@ public:
 			gui_render = true;
 			gui_dark_style = true;
 			gui_sequence_array_reserve_size = 50;
+			editor_asset_selection_button_size_multiplier = 2.0f;
 			editor_float_slider_speed = 0.01f;
 			editor_lua_variables_max_height = 200.0f;
 			editor_play_button_size = 30.0f;
@@ -952,9 +955,11 @@ public:
 			gui_file_dialog_dir_color_G = 0.623f;
 			gui_file_dialog_dir_color_B = 0.314f;
 			editor_button_add_texture = "buttons\\button_add_3.png";
+			editor_button_add_list_texture = "buttons\\button_add_from_list_1.png";
 			editor_button_delete_entry_texture = "buttons\\button_delete_5.png";
 			editor_button_gui_sequence_texture = "buttons\\button_gui_sequence_1.png";
 			editor_button_open_file_texture = "buttons\\button_open_file_1.png";
+			editor_button_open_asset_list_texture = "buttons\\button_add_from_list_1.png";
 			editor_button_pause_texture = "buttons\\button_editor_pause_2.png";
 			editor_button_play_texture = "buttons\\button_editor_play_2.png";
 			editor_button_reload_texture = "buttons\\button_reload_3.png";
@@ -966,6 +971,7 @@ public:
 		bool gui_render;
 		bool gui_dark_style;
 		int gui_sequence_array_reserve_size;
+		float editor_asset_selection_button_size_multiplier;
 		float editor_float_slider_speed;
 		float editor_lua_variables_max_height;
 		float editor_play_button_size;
@@ -975,9 +981,11 @@ public:
 		float gui_file_dialog_dir_color_G;
 		float gui_file_dialog_dir_color_B;
 		std::string editor_button_add_texture;
+		std::string editor_button_add_list_texture;
 		std::string editor_button_delete_entry_texture;
 		std::string editor_button_gui_sequence_texture;
 		std::string editor_button_open_file_texture;
+		std::string editor_button_open_asset_list_texture;
 		std::string editor_button_pause_texture;
 		std::string editor_button_play_texture;
 		std::string editor_button_reload_texture;

+ 333 - 69
Praxis3D/Source/EditorWindow.cpp

@@ -60,6 +60,9 @@ void EditorWindow::update(const float p_deltaTime)
     // Update the hierarchy list
     updateHierarchyList();
 
+    // Update the asset lists
+    updateAssetLists();
+
     static float f = 0.0f;
     static int counter = 0;
     ImGui::ShowDemoWindow();
@@ -159,6 +162,9 @@ void EditorWindow::update(const float p_deltaTime)
 
         if(ImGui::BeginMenu("File"))
         {
+            if(ImGui::MenuItem("New"))
+            {
+            }
             if(ImGui::MenuItem("Open...")) 
             {
                 // Only open the file browser if it's not opened already
@@ -173,6 +179,7 @@ void EditorWindow::update(const float p_deltaTime)
                     m_fileBrowserDialog.m_title = "Open scene";
                     m_fileBrowserDialog.m_name = "OpenSceneFileDialog";
                     m_fileBrowserDialog.m_rootPath = Config::filepathVar().map_path;
+                    m_fileBrowserDialog.m_flags = FileBrowserDialog::FileBrowserDialogFlags::FileBrowserDialogFlags_None;
 
                     // Tell the GUI scene to open the file browser
                     m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene, DataType::DataType_FileBrowserDialog, (void *)&m_fileBrowserDialog);
@@ -190,11 +197,11 @@ void EditorWindow::update(const float p_deltaTime)
 
                     // Define file browser variables
                     m_fileBrowserDialog.m_definedFilename = m_systemScene->getSceneLoader()->getSceneFilename();
-                    m_fileBrowserDialog.m_flags = FileBrowserDialog::FileBrowserDialogFlags::FileBrowserDialogFlags_ConfirmOverwrite;
                     m_fileBrowserDialog.m_filter = ".pmap,.*";
                     m_fileBrowserDialog.m_title = "Save scene";
                     m_fileBrowserDialog.m_name = "SaveSceneFileDialog";
                     m_fileBrowserDialog.m_rootPath = Config::filepathVar().map_path;
+                    m_fileBrowserDialog.m_flags = FileBrowserDialog::FileBrowserDialogFlags::FileBrowserDialogFlags_ConfirmOverwrite;
                     
                     // Tell the GUI scene to open the file browser
                     m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene, DataType::DataType_FileBrowserDialog, (void *)&m_fileBrowserDialog);
@@ -667,38 +674,67 @@ void EditorWindow::update(const float p_deltaTime)
                     {
                         if(ImGui::CollapsingHeader(GetString(Properties::PropertyID::ModelComponent), ImGuiTreeNodeFlags_DefaultOpen))
                         {
-                            auto &currentModelData = modelComponent->getModelData();
-                            if(m_selectedEntity.m_modelDataPointer != &currentModelData)
-                            {
-                                m_selectedEntity.m_modelData.clear();
-                                m_selectedEntity.m_modelData = currentModelData;
-                                m_selectedEntity.m_modelDataPointer = &currentModelData;
+                            bool modelComponentDataNeedsUpdating = false;
 
-                                m_selectedEntity.m_modelFilenames.clear();
-                                for(decltype(m_selectedEntity.m_modelData.size()) modelSize = m_selectedEntity.m_modelData.size(), modelIndex = 0; modelIndex < modelSize; modelIndex++)
+                            // If the model data was modified, send the new data to the ModelComponent
+                            if(m_selectedEntity.m_modelDataModified)
+                            {
+                                m_systemScene->getSceneLoader()->getChangeController()->sendData(modelComponent, DataType::DataType_ModelsProperties, (void *)&m_selectedEntity.m_componentData.m_graphicsComponents.m_modelConstructionInfo->m_modelsProperties);
+                                m_selectedEntity.m_modelDataModified = false;
+                            }
+                            else
+                            {
+                                // If the model data was recreated (meaning model data was changed), update the ModelComponent data
+                                auto &currentModelData = modelComponent->getModelData();
+                                if(m_selectedEntity.m_modelDataPointer != &currentModelData)
                                 {
-                                    m_selectedEntity.m_modelFilenames.push_back(m_selectedEntity.m_modelData[modelIndex].m_model.getFilename());
+                                    m_selectedEntity.m_modelDataPointer = &currentModelData;
+                                    modelComponentDataNeedsUpdating = true;
                                 }
+                                else
+                                {
+                                    // If ModelComponent has been loaded after sending it new data, update the ModelComponent data
+                                    if(m_selectedEntity.m_modelDataUpdateAfterLoading)
+                                        if(modelComponent->isLoadedToMemory())
+                                        {
+                                            m_selectedEntity.m_modelDataUpdateAfterLoading = false;
+                                            modelComponentDataNeedsUpdating = true;
+                                        }
+                                }
+                            }
+
+                            // Update the Models Properties of the currently selected ModelComponent
+                            if(modelComponentDataNeedsUpdating)
+                            {
+                                m_selectedEntity.m_componentData.m_graphicsComponents.m_modelConstructionInfo->m_modelsProperties.m_models.clear();
+                                modelComponent->getModelsProperties(m_selectedEntity.m_componentData.m_graphicsComponents.m_modelConstructionInfo->m_modelsProperties);
                             }
 
                             // Go over each model
-                            for(decltype(m_selectedEntity.m_modelData.size()) modelSize = m_selectedEntity.m_modelData.size(), modelIndex = 0; modelIndex < modelSize; modelIndex++)
+                            for(decltype(m_selectedEntity.m_componentData.m_graphicsComponents.m_modelConstructionInfo->m_modelsProperties.m_models.size()) modelSize = m_selectedEntity.m_componentData.m_graphicsComponents.m_modelConstructionInfo->m_modelsProperties.m_models.size(), 
+                                modelIndex = 0; modelIndex < modelSize; modelIndex++)
                             {
+                                auto &modelEntry = m_selectedEntity.m_componentData.m_graphicsComponents.m_modelConstructionInfo->m_modelsProperties.m_models[modelIndex];
+
                                 // Draw MODEL FILENAME
-                                drawLeftAlignedLabelText("Filename:", inputWidgetOffset, calcTextSizedButtonOffset(1) - inputWidgetOffset - m_imguiStyle.FramePadding.x);
-                                if(ImGui::InputText(("##" + Utilities::toString(modelIndex) + "ModelFileInput").c_str(), &m_selectedEntity.m_modelFilenames[modelIndex], ImGuiInputTextFlags_EnterReturnsTrue))
+                                drawLeftAlignedLabelText("Filename:", inputWidgetOffset, calcTextSizedButtonOffset(2) - inputWidgetOffset - m_imguiStyle.FramePadding.x);
+                                if(ImGui::InputText(("##" + Utilities::toString(modelIndex) + "ModelFileInput").c_str(), &modelEntry.m_modelName, ImGuiInputTextFlags_EnterReturnsTrue))
                                 {
-                                    // If the sound filename was changed, send a notification to the Sound Component
+                                    // If the model filename was changed, set the modified flag
+                                    m_selectedEntity.m_modelDataModified = true;
                                 }
 
                                 // Draw MODEL OPEN button
-                                ImGui::SameLine(calcTextSizedButtonOffset(1));
-                                if(drawTextSizedButton(m_buttonTextures[ButtonTextureType::ButtonTextureType_OpenFile], "##" + Utilities::toString(modelIndex) + "ModelFileOpenButton", "Open a model file"))
+                                ImGui::SameLine(calcTextSizedButtonOffset(2));
+                                if(drawTextSizedButton(m_buttonTextures[ButtonTextureType::ButtonTextureType_OpenFile], "##ModelFileOpenButton", "Open a model file"))
                                 {
                                     // Only open the file browser if it's not opened already
                                     if(m_currentlyOpenedFileBrowser == FileBrowserActivated::FileBrowserActivated_None)
                                     {
-                                        // Set the file browser activation to Lua Script
+                                        // Set the selected model filename handle
+                                        m_selectedEntity.m_selectedModelName = &modelEntry.m_modelName;
+
+                                        // Set the file browser activation to Model File
                                         m_currentlyOpenedFileBrowser = FileBrowserActivated::FileBrowserActivated_ModelFile;
 
                                         // Define file browser variables
@@ -706,41 +742,93 @@ void EditorWindow::update(const float p_deltaTime)
                                         m_fileBrowserDialog.m_title = "Open a model file";
                                         m_fileBrowserDialog.m_name = "OpenModelFileFileDialog";
                                         m_fileBrowserDialog.m_rootPath = Config::filepathVar().model_path;
+                                        m_fileBrowserDialog.m_flags = FileBrowserDialog::FileBrowserDialogFlags::FileBrowserDialogFlags_None;
 
                                         // Tell the GUI scene to open the file browser
                                         m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene, DataType::DataType_FileBrowserDialog, (void *)&m_fileBrowserDialog);
                                     }
                                 }
 
+                                const std::string modelSelectionPopupName = "##" + Utilities::toString(modelIndex) + "ModelSelectionPopup";
+
+                                // Draw OPEN ASSET LIST button
+                                ImGui::SameLine(calcTextSizedButtonOffset(1));
+                                if(drawTextSizedButton(m_buttonTextures[ButtonTextureType::ButtonTextureType_OpenAssetList], "##" + Utilities::toString(modelIndex) + "ModelOpenAssetListButton", "Choose a model from the loaded assets"))
+                                {
+                                    // Open the pop-up with the model asset list
+                                    ImGui::OpenPopup(modelSelectionPopupName.c_str());
+                                }
+
                                 // Draw MODEL RELOAD button
                                 ImGui::SameLine(calcTextSizedButtonOffset(0));
                                 if(drawTextSizedButton(m_buttonTextures[ButtonTextureType::ButtonTextureType_Reload], "##" + Utilities::toString(modelIndex) + "ModelFileReloadButton", "Reload the model file"))
                                 {
-                                    // Send a reload notification to the Sound Component
-                                    //m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::Reload);
+                                    // Set the modified flag
+                                    m_selectedEntity.m_modelDataModified = true;
+                                }
+
+                                // Draw MODEL ASSET LIST
+                                if(ImGui::BeginPopup(modelSelectionPopupName.c_str()))
+                                {
+                                    // Calculate the text size based on the longest model asset name
+                                    ImVec2 nameTextSize(ImGui::CalcTextSize(m_modelAssetLongestName.c_str()).x + m_imguiStyle.FramePadding.x * 2.0f, m_assetSelectionPopupImageSize.y);
+
+                                    // Remove selection border and align text vertically
+                                    ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f));
+                                    ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
+
+                                    for(decltype(m_modelAssets.size()) i = 0, size = m_modelAssets.size(); i < size; i++)
+                                    {
+                                        // Draw MODEL NAME selection
+                                        // Set the text height to the texture image button height
+                                        if(ImGui::Selectable(m_modelAssets[i].second.c_str(), (modelEntry.m_modelName == m_modelAssets[i].second), 0, nameTextSize))
+                                        {
+                                            // Set the selected model
+                                            modelEntry.m_modelName = m_modelAssets[i].second;
+
+                                            // Set the modified flag
+                                            m_selectedEntity.m_modelDataModified = true;
+                                        }
+                                    }
+                                    ImGui::PopStyleVar(2); //ImGuiStyleVar_SelectableTextAlign, ImGuiStyleVar_FramePadding
+                                    ImGui::EndPopup();
                                 }
 
                                 ImGui::PushStyleVar(ImGuiStyleVar_SeparatorTextAlign, ImVec2(0.5f, 0.5f));
-                                for(decltype(m_selectedEntity.m_modelData[modelIndex].m_meshes.size()) meshSize = m_selectedEntity.m_modelData[modelIndex].m_meshes.size(), meshIndex = 0; meshIndex < meshSize; meshIndex++)
+                                for(decltype(modelEntry.m_numOfMeshes) meshSize = modelEntry.m_numOfMeshes, meshIndex = 0; meshIndex < meshSize; meshIndex++)
                                 {
-                                    //ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_Leaf
+                                    // Get the mesh name
+                                    std::string meshName = modelEntry.m_meshNames[meshIndex];
+                                    if(!meshName.empty())
+                                        meshName = " (" + meshName + ")";
 
-                                    if(ImGui::TreeNodeEx(("Mesh " + Utilities::toString(meshIndex) + ":").c_str(), ImGuiTreeNodeFlags_SpanAvailWidth))
+                                    // Draw MESH
+                                    if(ImGui::TreeNodeEx(("Mesh " + Utilities::toString(meshIndex) + meshName + ":").c_str(), ImGuiTreeNodeFlags_SpanAvailWidth)) // ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_Leaf
                                     {
                                         ImGui::SeparatorText("Mesh settings:");
 
                                         // Draw HEIGHT SCALE
                                         drawLeftAlignedLabelText("Height scale:", inputWidgetOffset);
-                                        if(ImGui::DragFloat(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + "HeightScaleDrag").c_str(), &m_selectedEntity.m_modelData[modelIndex].m_meshes[meshIndex].m_heightScale, Config::GUIVar().editor_float_slider_speed, 0.0f, 100000.0f))
+                                        if(ImGui::DragFloat(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + "HeightScaleDrag").c_str(), &modelEntry.m_heightScale[meshIndex], Config::GUIVar().editor_float_slider_speed, 0.0f, 100000.0f))
                                         {
-                                            // If the sound volume was changed, send a notification to the Sound Component
+                                            // If the height scale was changed, set the modified flag
+                                            m_selectedEntity.m_modelDataModified = true;
                                         }
 
                                         // Draw ALPHA THRESHOLD
                                         drawLeftAlignedLabelText("Alpha Threshold:", inputWidgetOffset);
-                                        if(ImGui::DragFloat(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + "AlphaThresholdDrag").c_str(), &m_selectedEntity.m_modelData[modelIndex].m_meshes[meshIndex].m_alphaThreshold, Config::GUIVar().editor_float_slider_speed, 0.0f, 1.0f))
+                                        if(ImGui::DragFloat(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + "AlphaThresholdDrag").c_str(), &modelEntry.m_alphaThreshold[meshIndex], Config::GUIVar().editor_float_slider_speed, 0.0f, 1.0f))
+                                        {
+                                            // If the alpha threshold was changed, set the modified flag
+                                            m_selectedEntity.m_modelDataModified = true;
+                                        }
+
+                                        // Draw EMISSIVE INTENSITY
+                                        drawLeftAlignedLabelText("Emissive intensity:", inputWidgetOffset);
+                                        if(ImGui::DragFloat(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + "EmissiveIntensityDrag").c_str(), &modelEntry.m_emissiveIntensity[meshIndex], Config::GUIVar().editor_float_slider_speed, 0.0f, 100000.0f))
                                         {
-                                            // If the sound volume was changed, send a notification to the Sound Component
+                                            // If the emissive intensity was changed, set the modified flag
+                                            m_selectedEntity.m_modelDataModified = true;
                                         }
 
                                         for(unsigned int materialIndex = 0; materialIndex < MaterialType::MaterialType_NumOfTypes; materialIndex++)
@@ -767,47 +855,112 @@ void EditorWindow::update(const float p_deltaTime)
                                             ImGui::SeparatorText(materialTypeName.c_str());
 
                                             // Draw TEXTURE FILENAME
-                                            std::string filename = m_selectedEntity.m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_texture.getFilename();
-                                            drawLeftAlignedLabelText("Filename:", inputWidgetOffset, calcTextSizedButtonOffset(1) - inputWidgetOffset - m_imguiStyle.FramePadding.x + m_imguiStyle.IndentSpacing);
-                                            if(ImGui::InputText(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + Utilities::toString(materialIndex) + "TextureFilenameInput").c_str(), &filename, ImGuiInputTextFlags_EnterReturnsTrue))
+                                            drawLeftAlignedLabelText("Filename:", inputWidgetOffset, calcTextSizedButtonOffset(2) - inputWidgetOffset - m_imguiStyle.FramePadding.x + m_imguiStyle.IndentSpacing);
+                                            if(ImGui::InputText(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + Utilities::toString(materialIndex) + "TextureFilenameInput").c_str(), &modelEntry.m_meshMaterials[meshIndex][materialIndex], ImGuiInputTextFlags_EnterReturnsTrue))
                                             {
-                                                // If the sound filename was changed, send a notification to the Sound Component
-                                            }                                
-                                            
+                                                // If the texture filename was changed, set the modified flag
+                                                m_selectedEntity.m_modelDataModified = true;
+                                            }
+
                                             // Draw TEXTURE OPEN button
-                                            ImGui::SameLine(calcTextSizedButtonOffset(1) + m_imguiStyle.IndentSpacing);
+                                            ImGui::SameLine(calcTextSizedButtonOffset(2) + m_imguiStyle.IndentSpacing);
                                             if(drawTextSizedButton(m_buttonTextures[ButtonTextureType::ButtonTextureType_OpenFile], "##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + Utilities::toString(materialIndex) + "TextureOpenButton", "Open a texture file"))
                                             {
                                                 // Only open the file browser if it's not opened already
-                                                //if(m_currentlyOpenedFileBrowser == FileBrowserActivated::FileBrowserActivated_None)
-                                                //{
-                                                //    // Set the file browser activation to Lua Script
-                                                //    m_currentlyOpenedFileBrowser = FileBrowserActivated::FileBrowserActivated_ModelFile;
-
-                                                //    // Define file browser variables
-                                                //    m_fileBrowserDialog.m_filter = "Model files (.obj .3ds .fbx){.obj,.3ds,.fbx},All files{.*}";
-                                                //    m_fileBrowserDialog.m_title = "Open a model file";
-                                                //    m_fileBrowserDialog.m_name = "OpenModelFileFileDialog";
-                                                //    m_fileBrowserDialog.m_rootPath = Config::filepathVar().model_path;
-
-                                                //    // Tell the GUI scene to open the file browser
-                                                //    m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene, DataType::DataType_FileBrowserDialog, (void *)&m_fileBrowserDialog);
-                                                //}
+                                                if(m_currentlyOpenedFileBrowser == FileBrowserActivated::FileBrowserActivated_None)
+                                                {
+                                                    // Set the selected texture filename handle
+                                                    m_selectedEntity.m_selectedTextureName = &modelEntry.m_meshMaterials[meshIndex][materialIndex];
+
+                                                    // Set the file browser activation to Texture File
+                                                    m_currentlyOpenedFileBrowser = FileBrowserActivated::FileBrowserActivated_TextureFile;
+
+                                                    // Define file browser variables
+                                                    m_fileBrowserDialog.m_filter = "Texture files (.png .tga .tif .tiff .jpg .jpeg .bmp){.png,.tga,.tif,.tiff,.jpg,.jpeg,.bmp},All files{.*}";
+                                                    m_fileBrowserDialog.m_title = "Open a texture file";
+                                                    m_fileBrowserDialog.m_name = "OpenTextureFileFileDialog";
+                                                    m_fileBrowserDialog.m_rootPath = Config::filepathVar().texture_path;
+                                                    m_fileBrowserDialog.m_flags = FileBrowserDialog::FileBrowserDialogFlags::FileBrowserDialogFlags_None;
+
+                                                    // Tell the GUI scene to open the file browser
+                                                    m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene, DataType::DataType_FileBrowserDialog, (void *)&m_fileBrowserDialog);
+                                                }
+                                            }
+
+                                            const std::string textureSelectionPopupName = "##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + Utilities::toString(materialIndex) + "TextureSelectionPopup";
+
+                                            // Draw OPEN ASSET LIST button
+                                            ImGui::SameLine(calcTextSizedButtonOffset(1) + m_imguiStyle.IndentSpacing);
+                                            if(drawTextSizedButton(m_buttonTextures[ButtonTextureType::ButtonTextureType_OpenAssetList], "##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + Utilities::toString(materialIndex) + "TextureOpenAssetListButton", "Choose a texture from the loaded assets"))
+                                            {
+                                                // Open the pop-up with the texture asset list
+                                                ImGui::OpenPopup(textureSelectionPopupName.c_str());
                                             }
 
                                             // Draw TEXTURE RELOAD button
                                             ImGui::SameLine(calcTextSizedButtonOffset(0) + m_imguiStyle.IndentSpacing);
-                                            //ImGui::SameLine(ImGui::GetWindowWidth());// -m_buttonSizedByFont.x - m_imguiStyle.FramePadding.x - (m_buttonSizedByFont.x + m_imguiStyle.FramePadding.x * 3) * 0);
                                             if(drawTextSizedButton(m_buttonTextures[ButtonTextureType::ButtonTextureType_Reload], "##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + Utilities::toString(materialIndex) + "TextureReloadButton", "Reload the texture file"))
                                             {
-                                                // Send a reload notification to the Sound Component
-                                                //m_systemScene->getSceneLoader()->getChangeController()->sendChange(this, soundComponent, Systems::Changes::Audio::Reload);
+                                                // Set the modified flag
+                                                m_selectedEntity.m_modelDataModified = true;
                                             }
 
-                                            drawLeftAlignedLabelText("Texture scale:", inputWidgetOffset);
-                                            if(ImGui::DragFloat2(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + Utilities::toString(materialIndex) + "TextureScaleDrag").c_str(), glm::value_ptr(m_selectedEntity.m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_textureScale), Config::GUIVar().editor_float_slider_speed))
+                                            // Draw TEXTURE ASSET LIST
+                                            if(ImGui::BeginPopup(textureSelectionPopupName.c_str()))
                                             {
+                                                // Calculate the text size based on the longest texture asset name and the height of the texture image
+                                                ImVec2 nameTextSize(ImGui::CalcTextSize(m_textureAssetLongestName.c_str()).x + m_imguiStyle.FramePadding.x * 2.0f, m_assetSelectionPopupImageSize.y);
+
+                                                // Make button background transparent, remove button and selection border and align selection text vertically
+                                                ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
+                                                ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
+                                                ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f));
 
+                                                for(decltype(m_textureAssets.size()) i = 0, size = m_textureAssets.size(); i < size; i++)
+                                                {
+                                                    if(m_textureAssets[i].first->isLoadedFromFile())
+                                                    {
+                                                        // Draw TEXTURE IMAGE
+                                                        if(ImGui::ImageButton((textureSelectionPopupName + "Image").c_str(),
+                                                            (ImTextureID)m_textureAssets[i].first->getHandle(),
+                                                            m_assetSelectionPopupImageSize,
+                                                            ImVec2(0, 1),
+                                                            ImVec2(1, 0),
+                                                            ImVec4(0.0f, 0.0f, 0.0f, 0.0f)))
+                                                        {
+                                                            // Set the selected texture
+                                                            modelEntry.m_meshMaterials[meshIndex][materialIndex] = m_textureAssets[i].second;
+
+                                                            // Set the modified flag
+                                                            m_selectedEntity.m_modelDataModified = true;
+
+                                                            ImGui::CloseCurrentPopup();
+                                                        }
+
+                                                        ImGui::SameLine();
+
+                                                        // Draw TEXTURE NAME selection
+                                                        // Set the text height to the texture image button height
+                                                        if(ImGui::Selectable(m_textureAssets[i].second.c_str(), (modelEntry.m_meshMaterials[meshIndex][materialIndex] == m_textureAssets[i].second), 0, nameTextSize))
+                                                        {
+                                                            // Set the selected texture
+                                                            modelEntry.m_meshMaterials[meshIndex][materialIndex] = m_textureAssets[i].second;
+
+                                                            // Set the modified flag
+                                                            m_selectedEntity.m_modelDataModified = true;
+                                                        }
+                                                    }
+                                                }
+                                                ImGui::PopStyleVar(2); //ImGuiStyleVar_FramePadding, ImGuiStyleVar_SelectableTextAlign
+                                                ImGui::PopStyleColor(); //ImGuiCol_Button
+                                                ImGui::EndPopup();
+                                            }
+
+                                            drawLeftAlignedLabelText("Texture scale:", inputWidgetOffset);
+                                            if(ImGui::DragFloat2(("##" + Utilities::toString(modelIndex) + Utilities::toString(meshIndex) + Utilities::toString(materialIndex) + "TextureScaleDrag").c_str(), glm::value_ptr(modelEntry.m_meshMaterialsScale[meshIndex][materialIndex]), Config::GUIVar().editor_float_slider_speed))
+                                            {
+                                                // If the texture scale was changed, set the modified flag
+                                                m_selectedEntity.m_modelDataModified = true;
                                             }
                                         }
                                         ImGui::SeparatorText("");
@@ -817,7 +970,11 @@ void EditorWindow::update(const float p_deltaTime)
                                 ImGui::PopStyleVar(); // ImGuiStyleVar_SeparatorTextAlign
                             }
                         }
-                    }                    
+                    }
+
+                    {
+                    }
+
                     auto *shaderComponent = entityRegistry.try_get<ShaderComponent>(m_selectedEntity.m_entityID);
                     if(shaderComponent != nullptr)
                     {
@@ -1003,6 +1160,7 @@ void EditorWindow::update(const float p_deltaTime)
                                     m_fileBrowserDialog.m_title = "Open an audio file";
                                     m_fileBrowserDialog.m_name = "OpenAudioFileFileDialog";
                                     m_fileBrowserDialog.m_rootPath = Config::filepathVar().sound_path;
+                                    m_fileBrowserDialog.m_flags = FileBrowserDialog::FileBrowserDialogFlags::FileBrowserDialogFlags_None;
 
                                     // Tell the GUI scene to open the file browser
                                     m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene, DataType::DataType_FileBrowserDialog, (void *)&m_fileBrowserDialog);
@@ -1117,6 +1275,7 @@ void EditorWindow::update(const float p_deltaTime)
                                         m_fileBrowserDialog.m_title = "Open LUA script file";
                                         m_fileBrowserDialog.m_name = "OpenLuaScriptFileDialog";
                                         m_fileBrowserDialog.m_rootPath = Config::filepathVar().script_path;
+                                        m_fileBrowserDialog.m_flags = FileBrowserDialog::FileBrowserDialogFlags::FileBrowserDialogFlags_None;
 
                                         // Tell the GUI scene to open the file browser
                                         m_systemScene->getSceneLoader()->getChangeController()->sendData(m_systemScene, DataType::DataType_FileBrowserDialog, (void *)&m_fileBrowserDialog);
@@ -1409,19 +1568,17 @@ void EditorWindow::update(const float p_deltaTime)
             {
                 if(ImGui::BeginTabItem("Assets"))
                 {
-                    auto texturePool = Loaders::texture2D().getObjectPool();
-
                     // Draw each texture in the 2D texture loader pool
-                    for(decltype(texturePool.size()) i = 0, size = texturePool.size(); i < size; i++)
+                    for(decltype(m_textureAssets.size()) i = 0, size = m_textureAssets.size(); i < size; i++)
                     {
                         // Set each entry to be drawn on the same line (except the first entry)
                         if(i > 0)
                             ImGui::SameLine();
 
                         // Draw the texture
-                        if(ImGui::ImageButton((ImTextureID)texturePool[i]->getHandle(), ImVec2(60.0f, 60.0f), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f), 0))
+                        if(ImGui::ImageButton((ImTextureID)m_textureAssets[i].first->getHandle(), ImVec2(60.0f, 60.0f), ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f), 0))
                         {
-                            m_selectedTexture = texturePool[i];
+                            m_selectedTexture = m_textureAssets[i].first;
 
                             // Set the texture inspector tab flag to be selected (bring to focus), because a texture has just been selected
                             m_textureInspectorTabFlags = ImGuiTabItemFlags_SetSelected;
@@ -1439,16 +1596,16 @@ void EditorWindow::update(const float p_deltaTime)
                             ImGui::PopStyleVar();
                             ImGui::Separator();
 
-                            ImGui::Text(("Filename: " + texturePool[i]->getFilename()).c_str());
-                            ImGui::Text(("Size: " + Utilities::toString(texturePool[i]->getTextureWidth()) + "x" + Utilities::toString(texturePool[i]->getTextureHeight())).c_str());
+                            ImGui::Text(("Filename: " + m_textureAssets[i].second).c_str());
+                            ImGui::Text(("Size: " + Utilities::toString(m_textureAssets[i].first->getTextureWidth()) + "x" + Utilities::toString(m_textureAssets[i].first->getTextureHeight())).c_str());
 
-                            ImGui::Text(("Texture format: " + getTextureFormatString(texturePool[i]->getTextureFormat())).c_str());
-                            ImGui::Text(("Texture data type: " + getTextureDataTypeString(texturePool[i]->getTextureDataType())).c_str());
-                            ImGui::Text(("Texture data format: " + getTextureDataFormat(texturePool[i]->getTextureDataFormat())).c_str());
+                            ImGui::Text(("Texture format: " + getTextureFormatString(m_textureAssets[i].first->getTextureFormat())).c_str());
+                            ImGui::Text(("Texture data type: " + getTextureDataTypeString(m_textureAssets[i].first->getTextureDataType())).c_str());
+                            ImGui::Text(("Texture data format: " + getTextureDataFormat(m_textureAssets[i].first->getTextureDataFormat())).c_str());
 
-                            ImGui::Text(texturePool[i]->getMipmapEnabled() ? "Mipmap enabled" : "Mipmap disabled");
-                            if(texturePool[i]->getMipmapEnabled())
-                                ImGui::Text(("Mipmap level: " + Utilities::toString(texturePool[i]->getMipmapLevel())).c_str());
+                            ImGui::Text(m_textureAssets[i].first->getMipmapEnabled() ? "Mipmap enabled" : "Mipmap disabled");
+                            if(m_textureAssets[i].first->getMipmapEnabled())
+                                ImGui::Text(("Mipmap level: " + Utilities::toString(m_textureAssets[i].first->getMipmapLevel())).c_str());
 
                             ImGui::Separator();
 
@@ -1617,11 +1774,9 @@ void EditorWindow::update(const float p_deltaTime)
                 {
                     if(m_fileBrowserDialog.m_success)
                     {
-                        //m_systemScene->getSceneLoader()->loadFromFile(m_fileBrowserDialog.m_filename);
                         // Send a notification to the engine to reload the current engine state
                         m_systemScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(EngineChangeType::EngineChangeType_SceneFilename, EngineStateType::EngineStateType_Editor, m_fileBrowserDialog.m_filename));
                         m_systemScene->getSceneLoader()->getChangeController()->sendEngineChange(EngineChangeData(EngineChangeType::EngineChangeType_SceneReload));
-
                     }
 
                     // Reset the file browser and mark the file browser as not opened
@@ -1662,7 +1817,7 @@ void EditorWindow::update(const float p_deltaTime)
                             // Set the selected file path as a relative path from current directory
                             m_selectedEntity.m_componentData.m_audioComponents.m_soundConstructionInfo->m_soundFilename = m_fileBrowserDialog.m_filePathName.substr(currentDirectory.size());
 
-                            // If the Lua script filename was changed, send a notification to the LUA Component
+                            // If the Lua script filename was changed, set a flag for it
                             m_selectedEntity.m_soundFilenameModified = true;
                         }
                         else
@@ -1675,6 +1830,70 @@ void EditorWindow::update(const float p_deltaTime)
                 }
             }
             break;
+        case EditorWindow::FileBrowserActivated_ModelFile:
+            {
+                // If the file browser was activated and it is now closed, process the result
+                if(m_fileBrowserDialog.m_closed)
+                {
+                    if(m_fileBrowserDialog.m_success)
+                    {
+                        // Get the current directory path
+                        const std::string currentDirectory = Filesystem::getCurrentDirectory() + "\\" + Config::filepathVar().model_path;
+
+                        // Check if the selected file is within the current directory
+                        if(m_fileBrowserDialog.m_filePathName.rfind(currentDirectory, 0) == 0)
+                        {
+                            if(m_selectedEntity.m_selectedModelName != nullptr)
+                            {
+                                *m_selectedEntity.m_selectedModelName = m_fileBrowserDialog.m_filePathName.substr(currentDirectory.size());
+
+                                // If the model filename was changed, set a flag for it
+                                m_selectedEntity.m_modelDataModified = true;
+                                m_selectedEntity.m_modelDataUpdateAfterLoading = true;
+                            }
+                        }
+                        else
+                            ErrHandlerLoc::get().log(ErrorCode::Editor_path_outside_current_dir, ErrorSource::Source_GUIEditor);
+                    }
+
+                    // Reset the file browser and mark the file browser as not opened
+                    m_fileBrowserDialog.reset();
+                    m_currentlyOpenedFileBrowser = FileBrowserActivated::FileBrowserActivated_None;
+                }
+            }
+            break;
+        case EditorWindow::FileBrowserActivated_TextureFile:
+            {
+                // If the file browser was activated and it is now closed, process the result
+                if(m_fileBrowserDialog.m_closed)
+                {
+                    if(m_fileBrowserDialog.m_success)
+                    {
+                        // Get the current directory path
+                        const std::string currentDirectory = Filesystem::getCurrentDirectory() + "\\" + Config::filepathVar().texture_path;
+
+                        // Check if the selected file is within the current directory
+                        if(m_fileBrowserDialog.m_filePathName.rfind(currentDirectory, 0) == 0)
+                        {
+                            if(m_selectedEntity.m_selectedTextureName != nullptr)
+                            {
+                                *m_selectedEntity.m_selectedTextureName = m_fileBrowserDialog.m_filePathName.substr(currentDirectory.size());
+
+                                // If the texture filename was changed, set a flag for it
+                                m_selectedEntity.m_modelDataModified = true;
+                                m_selectedEntity.m_modelDataUpdateAfterLoading = true;
+                            }
+                        }
+                        else
+                            ErrHandlerLoc::get().log(ErrorCode::Editor_path_outside_current_dir, ErrorSource::Source_GUIEditor);
+                    }
+
+                    // Reset the file browser and mark the file browser as not opened
+                    m_fileBrowserDialog.reset();
+                    m_currentlyOpenedFileBrowser = FileBrowserActivated::FileBrowserActivated_None;
+                }
+            }
+            break;
     }
 }
 
@@ -1706,6 +1925,9 @@ void EditorWindow::setup(EditorWindowSettings &p_editorWindowSettings)
     m_buttonTextures.emplace_back(Loaders::texture2D().load(Config::GUIVar().editor_button_add_texture));
     m_buttonTextures.emplace_back(Loaders::texture2D().load(Config::GUIVar().editor_button_open_file_texture));
     m_buttonTextures.emplace_back(Loaders::texture2D().load(Config::GUIVar().editor_button_reload_texture));
+    m_buttonTextures.emplace_back(Loaders::texture2D().load(Config::GUIVar().editor_button_open_asset_list_texture));
+
+    assert(m_buttonTextures.size() == ButtonTextureType::ButtonTextureType_NumOfTypes && "m_buttonTextures array is different size than the number of button textures, in EditorWindow.cpp");
 
     // Load button textures to memory
     for(decltype(m_buttonTextures.size()) size = m_buttonTextures.size(), i = 0; i < size; i++)
@@ -1968,3 +2190,45 @@ void EditorWindow::updateComponentList()
         }
     }
 }
+
+void EditorWindow::updateAssetLists()
+{    
+    //	 ____________________________
+    //	|							 |
+    //	|	   TEXTURE ASSETS        |
+    //	|____________________________|
+    //
+    // Clear texture asset array
+    m_textureAssets.clear();
+
+    // Go over each texture in the loaders texture pool
+    auto texturePool = Loaders::texture2D().getObjectPool();
+    for(decltype(texturePool.size()) i = 0, size = texturePool.size(); i < size; i++)
+    {
+        m_textureAssets.push_back(std::make_pair(texturePool[i], texturePool[i]->getFilename()));
+
+        // Set the longest texture name from all loaded texture assets, required for setting popup sizes when showing the list of textures
+        if(m_textureAssetLongestName.size() < texturePool[i]->getFilename().size())
+            m_textureAssetLongestName = texturePool[i]->getFilename();
+    }
+
+
+    //	 ____________________________
+    //	|							 |
+    //	|	    MODEL ASSETS         |
+    //	|____________________________|
+    //
+    // Clear model asset array
+    m_modelAssets.clear();
+
+    // Go over each model in the loaders model pool
+    auto modelPool = Loaders::model().getObjectPool();
+    for(decltype(modelPool.size()) i = 0, size = modelPool.size(); i < size; i++)
+    {
+        m_modelAssets.push_back(std::make_pair(modelPool[i], modelPool[i]->getFilename()));
+
+        // Set the longest model name from all loaded model assets, required for setting popup sizes when showing the list of model
+        if(m_modelAssetLongestName.size() < modelPool[i]->getFilename().size())
+            m_modelAssetLongestName = modelPool[i]->getFilename();
+    }
+}

+ 23 - 10
Praxis3D/Source/EditorWindow.h

@@ -26,6 +26,7 @@ public:
 		m_GUISequenceEnabled = false;
 		m_LUAScriptingEnabled = true;
 		m_sceneState = EditorSceneState::EditorSceneState_Pause;
+		m_centerWindowSize = glm::ivec2(0);
 
 		m_selectedTexture = nullptr;
 		m_textureInspectorTabFlags = 0;
@@ -42,6 +43,7 @@ public:
 
 		m_fontSize = ImGui::GetFontSize();
 		m_buttonSizedByFont = ImVec2(m_fontSize, m_fontSize);
+		m_assetSelectionPopupImageSize = ImVec2(m_fontSize, m_fontSize) * Config::GUIVar().editor_asset_selection_button_size_multiplier;
 	}
 	~EditorWindow();
 
@@ -395,18 +397,13 @@ private:
 	{
 		SelectedEntity(const Observer &p_parent) : m_spatialDataManager(p_parent)
 		{ 
-			m_entityID = NULL_ENTITY_ID;
+			setEntity(NULL_ENTITY_ID);
 			m_playing = false;
-			m_soundFilenameModified = false;
 			m_soundType = SoundComponent::SoundType::SoundType_Null;
 			m_objectMaterialType = ObjectMaterialType::Concrete;
 			m_lightType = LightComponent::LightComponentType::LightComponentType_null;
-			m_modelDataPointer = nullptr;
 			m_collisionShapeType = RigidBodyComponent::CollisionShapeType::CollisionShapeType_Null;
 
-			m_luaVariablesModified = false;
-			m_luaScriptFilenameModified = false;
-
 			m_componentData.m_audioComponents.m_soundConstructionInfo = new SoundComponent::SoundComponentConstructionInfo();
 			m_componentData.m_audioComponents.m_soundListenerConstructionInfo = new SoundListenerComponent::SoundListenerComponentConstructionInfo();
 
@@ -430,9 +427,14 @@ private:
 		void setEntity(const EntityID p_entityID)
 		{
 			m_entityID = p_entityID;
-			m_soundFilenameModified = false;
 			m_luaVariablesModified = false;
 			m_luaScriptFilenameModified = false;
+			m_modelDataModified = false;
+			m_soundFilenameModified = false;
+			m_selectedModelName = nullptr;
+			m_selectedTextureName = nullptr;
+			m_modelDataPointer = nullptr;
+			m_modelDataUpdateAfterLoading = false;
 		}
 
 		void unselect()
@@ -449,7 +451,6 @@ private:
 
 		// SoundComponent data
 		bool m_playing;
-		bool m_soundFilenameModified;
 		int m_soundType;
 
 		// SpatialComponent data
@@ -462,9 +463,10 @@ private:
 		int m_lightType;
 
 		// ModelComponent data
-		std::vector<ModelData> m_modelData;
+		std::string *m_selectedModelName;
+		std::string *m_selectedTextureName;
 		std::vector<ModelData> const *m_modelDataPointer;
-		std::vector<std::string> m_modelFilenames;
+		bool m_modelDataUpdateAfterLoading;
 
 		// RigidBodyComponent data
 		int m_collisionShapeType;
@@ -474,6 +476,8 @@ private:
 
 		bool m_luaVariablesModified;
 		bool m_luaScriptFilenameModified;
+		bool m_modelDataModified;
+		bool m_soundFilenameModified;
 	};
 
 	enum ButtonTextureType : unsigned int
@@ -487,6 +491,7 @@ private:
 		ButtonTextureType_Add,
 		ButtonTextureType_OpenFile,
 		ButtonTextureType_Reload,
+		ButtonTextureType_OpenAssetList,
 		ButtonTextureType_NumOfTypes
 	};
 	enum EditorSceneState : unsigned int
@@ -558,6 +563,7 @@ private:
 	void updateEntityList();
 	void updateHierarchyList();
 	void updateComponentList();
+	void updateAssetLists();
 
 	inline std::string getTextureFormatString(const TextureFormat p_textureFormat) const
 	{
@@ -685,10 +691,17 @@ private:
 	FileBrowserActivated m_currentlyOpenedFileBrowser;
 	FileBrowserDialog m_fileBrowserDialog;
 	const ImVec2 m_playPauseButtonSize;
+	ImVec2 m_assetSelectionPopupImageSize;
 
 	// LUA variables editor data
 	std::vector<const char *> m_luaVariableTypeStrings;
 
+	// Assets variables
+	std::vector<std::pair<Texture2D *, std::string>> m_textureAssets;
+	std::vector<std::pair<Model *, std::string>> m_modelAssets;
+	std::string m_textureAssetLongestName;
+	std::string m_modelAssetLongestName;
+
 	// Texture inspector variables
 	Texture2D *m_selectedTexture;
 	ImGuiTabItemFlags m_textureInspectorTabFlags;

+ 5 - 0
Praxis3D/Source/ErrorCodes.h

@@ -38,6 +38,10 @@ DECLARE_ENUM(ErrorType, ERROR_TYPES)
     Code(Failure,) \
     Code(Initialize_success,) \
     Code(Initialize_failure,) \
+    Code(Load_success,) \
+    Code(Load_failure,) \
+    Code(Load_to_memory_success,) \
+    Code(Load_to_memory_failure,) \
     Code(File_not_found,) \
     Code(Filename_empty,) \
 	/* Audio system errors */\
@@ -81,6 +85,7 @@ DECLARE_ENUM(ErrorType, ERROR_TYPES)
 	Code(Shader_loading_failed,) \
 	/* Scene loader errors */ \
 	Code(GameObjects_missing,) \
+	Code(Number_of_meshes_missmatch,) \
 	/* Texture loader errors */ \
 	Code(Texture_not_found,) \
 	Code(Texture_empty,) \

+ 8 - 3
Praxis3D/Source/ErrorHandler.cpp

@@ -25,7 +25,11 @@ ErrorHandler::ErrorHandler()
 	AssignErrorType(Success, Info);
 	AssignErrorType(Failure, Warning);
 	AssignErrorType(Initialize_success, Info);
-	AssignErrorType(Initialize_failure, Info);
+	AssignErrorType(Initialize_failure, Warning);
+	AssignErrorType(Load_success, Info);
+	AssignErrorType(Load_failure, Warning);
+	AssignErrorType(Load_to_memory_success, Info);
+	AssignErrorType(Load_to_memory_failure, Warning);
 	AssignErrorType(File_not_found, Warning);
 	AssignErrorType(Filename_empty, Warning);
 	AssignErrorType(Audio_invalid_bus_type, Warning);
@@ -57,7 +61,8 @@ ErrorHandler::ErrorHandler()
 	AssignErrorType(Shader_link_failed, Error);
 	AssignErrorType(Shader_loading_failed, Error);
 	AssignErrorType(GameObjects_missing, Error);
-	AssignErrorType(Texture_not_found, Warning);
+	AssignErrorType(Number_of_meshes_missmatch, Warning);
+	AssignErrorType(Texture_not_found, Warning); 
 	AssignErrorType(Texture_empty, Warning);
 	AssignErrorType(Invalid_num_vid_displays, Warning);
 	AssignErrorType(SDL_video_init_failed, FatalError);
@@ -132,7 +137,7 @@ void ErrorHandler::log(ErrorCode p_errorCode, ErrorSource p_errorSource)
 		}
 	}
 	else
-		log(m_errorData[p_errorCode].m_errorType, p_errorSource, m_errorData[p_errorCode].m_errorString);
+		log(m_errorData[p_errorCode].m_errorType, p_errorSource, "\033[1;33m" + m_errorData[p_errorCode].m_errorString + "\033[0m");
 }
 void ErrorHandler::log(ErrorType p_errorType, ErrorSource p_errorSource, std::string p_error)
 {

+ 5 - 2
Praxis3D/Source/GraphicsDataSets.h

@@ -26,10 +26,11 @@ struct MaterialData
 // Contains data of a single mesh and its materials
 struct MeshData
 {
-	MeshData(const Model::Mesh &p_mesh, MaterialData p_materials[MaterialType::MaterialType_NumOfTypes], const float p_heightScale, const float p_alphaThreshold) : 
+	MeshData(const Model::Mesh &p_mesh, MaterialData p_materials[MaterialType::MaterialType_NumOfTypes], const float p_heightScale, const float p_alphaThreshold, const float p_emissiveIntensity) :
 		m_mesh(&p_mesh), 
 		m_heightScale(p_heightScale),
-		m_alphaThreshold(p_alphaThreshold) 
+		m_alphaThreshold(p_alphaThreshold),
+		m_emissiveIntensity(p_emissiveIntensity)
 	{
 		std::copy(p_materials, p_materials + MaterialType::MaterialType_NumOfTypes, m_materials);
 	}
@@ -38,6 +39,8 @@ struct MeshData
 	float m_heightScale;
 	// Transparency threshold after which the fragment is discarded
 	float m_alphaThreshold;
+	// Multiplier for emissive texture color
+	float m_emissiveIntensity;
 
 	// Handle to a mesh
 	const Model::Mesh *m_mesh;

+ 0 - 105
Praxis3D/Source/LightComponent.h

@@ -135,111 +135,6 @@ public:
 		return ErrorCode::Success;
 	}
 
-	ErrorCode importObject(const PropertySet &p_properties)
-	{
-		ErrorCode importError = ErrorCode::Failure;
-
-		// Check if light node is present and the component hasn't been loaded already
-		//if(p_properties && !isLoadedToMemory()) 
-		//{	
-		//	// Get the light type
-		//	auto const &type = p_properties.getPropertyByID(Properties::Type).getID();
-
-		//	// Load values based on the type of light
-		//	switch(type)
-		//	{
-		//	case Properties::DirectionalLight:
-		//		m_lightComponentType = LightComponentType::LightComponentType_directional;
-		//		m_objectType = Properties::PropertyID::DirectionalLight;
-
-		//		m_lightComponent.m_directional.m_color = p_properties.getPropertyByID(Properties::Color).getVec3f();
-		//		m_lightComponent.m_directional.m_intensity = p_properties.getPropertyByID(Properties::Intensity).getFloat();
-		//		setLoadedToMemory(true);
-		//		importError = ErrorCode::Success;
-
-		//		ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, m_name + " - Directional light loaded");
-		//		break;
-
-		//	case Properties::PointLight:
-		//		m_lightComponentType = LightComponentType::LightComponentType_point;
-		//		m_objectType = Properties::PropertyID::PointLight;
-
-		//		m_lightComponent.m_point.m_color = p_properties.getPropertyByID(Properties::Color).getVec3f();
-		//		m_lightComponent.m_point.m_intensity = p_properties.getPropertyByID(Properties::Intensity).getFloat();
-		//		setLoadedToMemory(true);
-		//		importError = ErrorCode::Success;
-
-		//		ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, m_name + " - Point light loaded");
-		//		break;
-
-		//	case Properties::SpotLight:
-		//		m_lightComponentType = LightComponentType::LightComponentType_spot;
-		//		m_objectType = Properties::PropertyID::SpotLight;
-
-		//		m_lightComponent.m_spot.m_color = p_properties.getPropertyByID(Properties::Color).getVec3f();
-		//		m_lightComponent.m_spot.m_cutoffAngle = p_properties.getPropertyByID(Properties::CutoffAngle).getFloat();
-		//		m_lightComponent.m_spot.m_intensity = p_properties.getPropertyByID(Properties::Intensity).getFloat();
-		//		setLoadedToMemory(true);
-		//		importError = ErrorCode::Success;
-
-		//		ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, m_name + " - Spot light loaded");
-		//		break;
-
-		//	default:
-		//		ErrHandlerLoc().get().log(ErrorType::Warning, ErrorSource::Source_LightComponent, m_name + " - missing \'Type\' identifier");
-		//		break;
-		//	}
-
-		//	if(importError == ErrorCode::Success)
-		//	{
-		//		setLoadedToMemory(true);
-		//		setLoadedToVideoMemory(true);
-		//		setActive(true);
-		//	}
-		//}
-		return importError;
-	}
-
-	PropertySet exportObject()
-	{
-		// Create the root Lighting property set
-		PropertySet propertySet(Properties::Lighting);
-
-		// Add the properties based on the type of light
-		//switch(getLightType())
-		//{
-		//case LightComponent::LightComponentType_directional:
-		//	propertySet.addProperty(Properties::Type, Properties::DirectionalLight);
-		//	propertySet.addProperty(Properties::Color, m_lightComponent.m_directional.m_color);
-		//	propertySet.addProperty(Properties::Intensity, m_lightComponent.m_directional.m_intensity);
-
-		//	ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, m_name + " - Directional light exported.");
-		//	break;
-
-		//case LightComponent::LightComponentType_point:
-		//	propertySet.addProperty(Properties::Type, Properties::PointLight);
-		//	propertySet.addProperty(Properties::Color, m_lightComponent.m_point.m_color);
-		//	propertySet.addProperty(Properties::Intensity, m_lightComponent.m_point.m_intensity);
-
-		//	ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, m_name + " - Point light exported.");
-		//	break;
-
-		//case LightComponent::LightComponentType_spot:
-		//	propertySet.addProperty(Properties::Type, Properties::SpotLight);
-		//	propertySet.addProperty(Properties::Color, m_lightComponent.m_spot.m_color);
-		//	propertySet.addProperty(Properties::CutoffAngle, m_lightComponent.m_spot.m_cutoffAngle);
-		//	propertySet.addProperty(Properties::Intensity, m_lightComponent.m_spot.m_intensity);
-
-		//	ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, m_name + " - Spot light exported.");
-		//	break;
-
-		//default:
-		//	break;
-		//}
-
-		return propertySet;
-	}
-
 	void loadToMemory() 
 	{
 		//updatePosition(glm::vec3(m_spatialData->getWorldTransform()[3]));

+ 323 - 236
Praxis3D/Source/ModelComponent.h

@@ -8,9 +8,9 @@ class ModelComponent : public SystemObject, public LoadableGraphicsObject
 {
 	friend class RendererScene;
 public:
-	struct MeshMaterialsProperties
+	struct MeshProperties
 	{
-		MeshMaterialsProperties()
+		MeshProperties()
 		{
 			m_numOfMeshes = 0;
 		}
@@ -21,13 +21,11 @@ public:
 			{
 				m_numOfMeshes = p_size;
 
-
 				// Resize mesh materials
 				if(p_size > m_meshMaterials.size())
 				{
 					std::vector<std::string> emptyStrings(MaterialType::MaterialType_NumOfTypes);
 					m_meshMaterials.resize(p_size, emptyStrings);
-					//m_meshMaterials.emplace_back(emptyStrings);
 				}
 
 				// Resize mesh materials scale and initialize each element to 1.0f
@@ -36,16 +34,16 @@ public:
 				{
 					std::vector<glm::vec2> emptyVec2(MaterialType::MaterialType_NumOfTypes, glm::vec2(1.0f, 1.0f));
 					m_meshMaterialsScale.resize(p_size, emptyVec2);
-
-					//for(size_t i = oldSize; i < p_size; i++)
-					//	for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
-					//		m_meshMaterialsScale[i][iMatType] = glm::vec2(1.0f, 1.0f);
 				}
 
 				// Resize mesh material alpha threshold and initialize each element to 0.0f
 				if(p_size > m_alphaThreshold.size())
 					m_alphaThreshold.resize(p_size, 0.0f);
 
+				// Resize mesh material emissive intensity initialize each element to 0.0f
+				if(p_size > m_emissiveIntensity.size())
+					m_emissiveIntensity.resize(p_size, 0.0f);
+
 				// Resize mesh material height scale and initialize each element to 1.0f
 				if(p_size > m_heightScale.size())
 					m_heightScale.resize(p_size, 1.0f);
@@ -56,16 +54,32 @@ public:
 			}
 		}
 
+		void clear()
+		{
+			m_numOfMeshes = 0;
+			m_modelName.clear();
+			m_meshMaterials.clear();
+			m_meshMaterialsScale.clear();
+			m_alphaThreshold.clear();
+			m_emissiveIntensity.clear();
+			m_heightScale.clear();
+			m_present.clear();
+		}
+
+		std::string m_modelName;
+
 		std::size_t m_numOfMeshes;
 		std::vector<std::vector<std::string>> m_meshMaterials;
 		std::vector<std::vector<glm::vec2>> m_meshMaterialsScale;
+		std::vector<std::string> m_meshNames;
 		std::vector<float> m_alphaThreshold;
+		std::vector<float> m_emissiveIntensity;
 		std::vector<float> m_heightScale;
 		std::vector<bool> m_present;
 	};
 	struct ModelsProperties
 	{
-		std::vector<std::string> m_modelNames;
+		std::vector<MeshProperties> m_models;
 	};
 
 	struct ModelComponentConstructionInfo : public SystemObject::SystemObjectConstructionInfo
@@ -76,13 +90,14 @@ public:
 		}
 
 		ModelsProperties m_modelsProperties;
-		MeshMaterialsProperties m_materialsFromProperties;
 	};
 
 	ModelComponent(SystemScene *p_systemScene, std::string p_name, const EntityID p_entityID, std::size_t p_id = 0) : SystemObject(p_systemScene, p_name, Properties::PropertyID::Models, p_entityID)
 	{
-		m_materialsFromProperties = nullptr;
 		m_modelsProperties = nullptr;
+		m_modelsNeedLoading = false;
+		m_texturesNeedLoading = false;
+		m_loadPending = false;
 	}
 	~ModelComponent() { }
 
@@ -90,12 +105,25 @@ public:
 
 	void loadToMemory()
 	{
+		importModels();
+		if(m_modelsNeedLoading)
+			loadModelsToMemory();
+
+		importTextures();
+		if(m_texturesNeedLoading)
+			loadTexturesToMemory();
+
+		return;
+
 		if(m_modelsProperties != nullptr)
 		{
-			for(decltype(m_modelsProperties->m_modelNames.size()) modelIndex = 0, modelSize = m_modelsProperties->m_modelNames.size(); modelIndex < modelSize; modelIndex++)
+			m_modelData.clear();
+
+			// Go over each model
+			for(decltype(m_modelsProperties->m_models.size()) modelIndex = 0, modelSize = m_modelsProperties->m_models.size(); modelIndex < modelSize; modelIndex++)
 			{
 				// Add a new model data entry, and get a reference to it
-				m_modelData.emplace_back(Loaders::model().load(m_modelsProperties->m_modelNames[modelIndex], false));
+				m_modelData.emplace_back(Loaders::model().load(m_modelsProperties->m_models[modelIndex].m_modelName, false));
 				auto &newModelData = m_modelData.back();
 
 				// Load the model to memory, to be able to access all of its meshes 
@@ -106,11 +134,12 @@ public:
 					// Get the material arrays that were loaded from the model file
 					auto &materialArrayFromModel = newModelData.m_model.getMaterialArrays();
 
+					// Go over each mesh
 					for(decltype(newModelData.m_model.getMeshSize()) meshIndex = 0, meshSize = newModelData.m_model.getMeshSize(); meshIndex < meshSize; meshIndex++)
 					{
-						if(m_materialsFromProperties != nullptr && m_materialsFromProperties->m_meshMaterials.size() > meshIndex)
+						if(m_modelsProperties->m_models[modelIndex].m_meshMaterials.size() > meshIndex)
 						{
-							if(m_materialsFromProperties->m_present[meshIndex] == true)
+							if(m_modelsProperties->m_models[modelIndex].m_present[meshIndex] == true)
 							{
 								// Define material data and material properties
 								MaterialData materials[MaterialType::MaterialType_NumOfTypes];
@@ -120,22 +149,26 @@ public:
 								{
 									auto filename = materialArrayFromModel.m_materials[iMatType][meshIndex].m_filename;
 
-									if(!m_materialsFromProperties->m_meshMaterials[meshIndex][iMatType].empty())
+									if(!m_modelsProperties->m_models[modelIndex].m_meshMaterials[meshIndex][iMatType].empty())
 									{
-										filename = m_materialsFromProperties->m_meshMaterials[meshIndex][iMatType];
+										filename = m_modelsProperties->m_models[modelIndex].m_meshMaterials[meshIndex][iMatType];
 									}
 
 									materials[iMatType].m_texture = Loaders::texture2D().load(filename, static_cast<MaterialType>(iMatType), false);
 									auto materialLoadError = materials[iMatType].m_texture.loadToMemory();
 
-									materials[iMatType].m_textureScale = m_materialsFromProperties->m_meshMaterialsScale[meshIndex][iMatType];
+									materials[iMatType].m_textureScale = m_modelsProperties->m_models[modelIndex].m_meshMaterialsScale[meshIndex][iMatType];
 								}
 
 								// Add the data for this mesh. Include materials loaded from the model itself, if they were present, otherwise, include default textures instead
-
-								newModelData.m_meshes.push_back(MeshData(newModelData.m_model.getMeshArray()[meshIndex], materials, m_materialsFromProperties->m_heightScale[meshIndex], m_materialsFromProperties->m_alphaThreshold[meshIndex]));
-
-								ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_ModelComponent, m_name + " - Model \'" + m_name + "\' loaded to memory");
+								newModelData.m_meshes.push_back(MeshData(
+									newModelData.m_model.getMeshArray()[meshIndex], 
+									materials, 
+									m_modelsProperties->m_models[modelIndex].m_heightScale[meshIndex], 
+									m_modelsProperties->m_models[modelIndex].m_alphaThreshold[meshIndex], 
+									m_modelsProperties->m_models[modelIndex].m_emissiveIntensity[meshIndex]));
+
+								ErrHandlerLoc::get().log(ErrorCode::Load_to_memory_success, ErrorSource::Source_ModelComponent, m_modelsProperties->m_models[modelIndex].m_modelName);
 							}
 						}
 						else
@@ -154,23 +187,22 @@ public:
 								materials[iMatType].m_textureScale = glm::vec2(Config::graphicsVar().texture_tiling_factor, Config::graphicsVar().texture_tiling_factor);
 							}
 
-							newModelData.m_meshes.push_back(MeshData(newModelData.m_model.getMeshArray()[meshIndex], materials, Config::graphicsVar().height_scale, Config::graphicsVar().alpha_threshold));
+							newModelData.m_meshes.push_back(MeshData(newModelData.m_model.getMeshArray()[meshIndex], materials, Config::graphicsVar().height_scale, Config::graphicsVar().alpha_threshold, Config::graphicsVar().emissive_multiplier));
 
-							ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_ModelComponent, m_name + " - Model \'" + m_name + "\' loaded to memory");
+							ErrHandlerLoc::get().log(ErrorCode::Load_to_memory_success, ErrorSource::Source_ModelComponent, m_modelsProperties->m_models[modelIndex].m_modelName);
 						}
 					}
 				}
+				else
+				{
+					ErrHandlerLoc::get().log(ErrorCode::Load_to_memory_failure, ErrorSource::Source_ModelComponent, m_modelsProperties->m_models[modelIndex].m_modelName);
+				}
 			}
 		}
 
 		// Set the component as loaded, because the load function was called
 		setLoadedToMemory(true);
 
-		if(m_materialsFromProperties != nullptr)
-		{
-			delete m_materialsFromProperties;
-			m_materialsFromProperties = nullptr;
-		}
 		if(m_modelsProperties != nullptr)
 		{
 			delete m_modelsProperties;
@@ -178,226 +210,187 @@ public:
 		}
 	}
 
-	BitMask getSystemType() { return Systems::Graphics; }
-
-	void update(const float p_deltaTime) { }
+	void importModels()
+	{
+		m_modelsNeedLoading = false;
 
-	BitMask getDesiredSystemChanges() { return Systems::Changes::None; }
+		if(m_modelsProperties != nullptr)
+		{
+			m_modelData.clear();
 
-	BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
+			// Go over each model
+			for(decltype(m_modelsProperties->m_models.size()) modelIndex = 0, modelSize = m_modelsProperties->m_models.size(); modelIndex < modelSize; modelIndex++)
+			{
+				// Add a new model data entry, and get a reference to it
+				m_modelData.emplace_back(Loaders::model().load(m_modelsProperties->m_models[modelIndex].m_modelName, false));
 
-	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
+				if(!m_modelData.back().m_model.isLoadedToMemory())
+					m_modelsNeedLoading = true;
+			}
+		}
+	}
 
-	ErrorCode importObject(const PropertySet &p_properties)
+	void importTextures()
 	{
-		ErrorCode importError = ErrorCode::Failure;
+		m_texturesNeedLoading = false;
 
-		// Check if models node is present and the component hasn't been loaded already
-		if(p_properties && !isLoadedToMemory())
+		if(m_modelsProperties != nullptr)
 		{
-			auto &modelsProperty = p_properties.getPropertySetByID(Properties::Models);
-
-			if(modelsProperty)
+			// Go over each model
+			for(decltype(m_modelsProperties->m_models.size()) modelIndex = 0, modelSize = m_modelsProperties->m_models.size(); modelIndex < modelSize; modelIndex++)
 			{
-				importError = ErrorCode::Success;
-
-				if(m_modelsProperties != nullptr)
-					delete m_modelsProperties;
+				auto &newModelData = m_modelData[modelIndex];
 
-				m_modelsProperties = new ModelsProperties();
+				// Get the material arrays that were loaded from the model file
+				auto &materialArrayFromModel = newModelData.m_model.getMaterialArrays();
 
-				// Loop over each model entry in the node
-				for(decltype(modelsProperty.getNumPropertySets()) iModel = 0, numModels = modelsProperty.getNumPropertySets(); iModel < numModels; iModel++)
+				// Go over each mesh
+				for(decltype(newModelData.m_model.getMeshSize()) meshIndex = 0, meshSize = newModelData.m_model.getMeshSize(); meshIndex < meshSize; meshIndex++)
 				{
-					// Get model filename
-					auto modelName = modelsProperty.getPropertySet(iModel).getPropertyByID(Properties::Filename).getString();
+					if(m_modelsProperties->m_models[modelIndex].m_meshMaterials.size() > meshIndex && m_modelsProperties->m_models[modelIndex].m_present[meshIndex] == true)
+					{
+						MaterialData materials[MaterialType::MaterialType_NumOfTypes];
 
-					// Add a new model data entry, and get a reference to it
-					//m_modelData.emplace_back(Loaders::model().load(modelName, false));
-					m_modelsProperties->m_modelNames.push_back(modelName);
-					//auto &newModelData = m_modelData.back();
+						// Go over each material type
+						for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
+						{
+							auto filename = materialArrayFromModel.m_materials[iMatType][meshIndex].m_filename;
 
-					// Load the model to memory, to be able to access all of its meshes
-					//auto modelLoadError = newModelData.m_model.loadToMemory();
+							if(!m_modelsProperties->m_models[modelIndex].m_meshMaterials[meshIndex][iMatType].empty())
+							{
+								filename = m_modelsProperties->m_models[modelIndex].m_meshMaterials[meshIndex][iMatType];
+							}
 
-					//if(modelLoadError == ErrorCode::Success)
-					//{
-						// Set the component as not being empty anymore, since a model has been loaded successfully
-						//setEmpty(false);
+							materials[iMatType].m_texture = Loaders::texture2D().load(filename, static_cast<MaterialType>(iMatType), false);
 
-						// Get the meshes array
-						//const std::vector<Model::Mesh> &meshesInModelArray = newModelData.m_model.getMeshArray();
+							if(!materials[iMatType].m_texture.isLoadedToMemory())
+								m_texturesNeedLoading = true;
 
-						// Get the meshes array
-					auto &meshesProperty = modelsProperty.getPropertySet(iModel).getPropertySetByID(Properties::Meshes);
+							materials[iMatType].m_textureScale = m_modelsProperties->m_models[modelIndex].m_meshMaterialsScale[meshIndex][iMatType];
+						}
 
-					// Check if the meshes array node is present;
-					// If it is present, only add the meshes included in the meshes node
-					// If it is not present, add all the meshes included in the model
-					if(meshesProperty)
+						// Add the data for this mesh. Include materials loaded from the model itself, if they were present, otherwise, include default textures instead
+						newModelData.m_meshes.push_back(MeshData(
+							newModelData.m_model.getMeshArray()[meshIndex],
+							materials,
+							m_modelsProperties->m_models[modelIndex].m_heightScale[meshIndex],
+							m_modelsProperties->m_models[modelIndex].m_alphaThreshold[meshIndex],
+							m_modelsProperties->m_models[modelIndex].m_emissiveIntensity[meshIndex]));
+					}
+					else
 					{
-						if(meshesProperty.getNumPropertySets() > 0)
-						{
-							m_materialsFromProperties = new MeshMaterialsProperties();
-
-							// Loop over each mesh entry in the model node
-							for(decltype(meshesProperty.getNumPropertySets()) iMesh = 0, numMeshes = meshesProperty.getNumPropertySets(); iMesh < numMeshes; iMesh++)
-							{
-								// Try to get the mesh index property node and check if it is present
-								auto &meshIndexProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::Index);
-								if(meshIndexProperty)
-								{
-									// Get the mesh index, check if it is valid and within the range of mesh array that was loaded from the model
-									const int meshDataIndex = meshIndexProperty.getInt();
+						// Define material data and material properties
+						MaterialData materials[MaterialType::MaterialType_NumOfTypes];
 
-									// Make sure the meshMaterials vector can fit the given mesh index
-									if(meshDataIndex >= m_materialsFromProperties->m_meshMaterials.size())
-									{
-										m_materialsFromProperties->resize(meshDataIndex + 1);
-										m_materialsFromProperties->m_present[meshDataIndex] = true;
-									}
-
-									// Get material alpha threshold value, if it is present
-									auto alphaThresholdProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::AlphaThreshold);
-									if(alphaThresholdProperty)
-										m_materialsFromProperties->m_alphaThreshold[meshDataIndex] = alphaThresholdProperty.getFloat();
+						// Go over each material type
+						for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
+						{
+							auto filename = materialArrayFromModel.m_materials[iMatType][meshIndex].m_filename;
 
-									// Get material height scale value, if it is present
-									auto heightScaleProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::HeightScale);
-									if(heightScaleProperty)
-										m_materialsFromProperties->m_heightScale[meshDataIndex] = heightScaleProperty.getFloat();
+							materials[iMatType].m_texture = Loaders::texture2D().load(filename, static_cast<MaterialType>(iMatType), false);
 
-									// Get material properties
-									auto materialsProperty = meshesProperty.getPropertySet(iMesh).getPropertySetByID(Properties::Materials);
+							if(!materials[iMatType].m_texture.isLoadedToMemory())
+								m_texturesNeedLoading = true;
 
-									// Define material data and material properties
-									MaterialData materials[MaterialType::MaterialType_NumOfTypes];
-									PropertySet materialProperties[MaterialType::MaterialType_NumOfTypes] =
-									{
-										materialsProperty.getPropertySetByID(Properties::Diffuse),
-										materialsProperty.getPropertySetByID(Properties::Normal),
-										materialsProperty.getPropertySetByID(Properties::Emissive),
-										materialsProperty.getPropertySetByID(Properties::RMHAO)
-									};
-
-									// Go over each material type
-									for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
-									{
-										// Check if an entry for the current material type was present within the properties
-										if(materialProperties[iMatType])
-										{
-											// Get texture filename property, check if it is valid
-											auto filenameProperty = materialProperties[iMatType].getPropertyByID(Properties::Filename);
-											if(filenameProperty.isVariableTypeString())
-											{
-												// Get texture filename string, check if it is valid
-												m_materialsFromProperties->m_meshMaterials[meshDataIndex][iMatType] = filenameProperty.getString();
-											}
-
-											// Get texture scale property, check if it is valid
-											auto scaleProperty = materialProperties[iMatType].getPropertyByID(Properties::TextureScale);
-											if(scaleProperty)
-												m_materialsFromProperties->m_meshMaterialsScale[meshDataIndex][iMatType] = scaleProperty.getVec2f();
-										}
-									}
-								}
-							}
+							materials[iMatType].m_textureScale = glm::vec2(Config::graphicsVar().texture_tiling_factor, Config::graphicsVar().texture_tiling_factor);
 						}
 
-						/*/ Loop over each mesh entry in the model node
-						for(decltype(meshesProperty.getNumPropertySets()) iMesh = 0, numMeshes = meshesProperty.getNumPropertySets(); iMesh < numMeshes; iMesh++)
-						{
-							// Try to get the mesh index property node and check if it is present
-							auto &meshIndexProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::Index);
-							if(meshIndexProperty)
-							{
-								// Get the mesh index, check if it is valid and within the range of mesh array that was loaded from the model
-								const int meshDataIndex = meshIndexProperty.getInt();
-								if(meshDataIndex >= 0 && meshDataIndex < meshesInModelArray.size())
-								{
-									// Get material properties
-									auto materialsProperty = meshesProperty.getPropertySet(iMesh).getPropertySetByID(Properties::Materials);
+						newModelData.m_meshes.push_back(MeshData(newModelData.m_model.getMeshArray()[meshIndex], materials, Config::graphicsVar().height_scale, Config::graphicsVar().alpha_threshold, Config::graphicsVar().emissive_multiplier));
 
-									// Define material data and material properties
-									MaterialData materials[MaterialType::MaterialType_NumOfTypes];
-									PropertySet materialProperties[MaterialType::MaterialType_NumOfTypes] =
-									{
-										materialsProperty.getPropertySetByID(Properties::Diffuse),
-										materialsProperty.getPropertySetByID(Properties::Normal),
-										materialsProperty.getPropertySetByID(Properties::Emissive),
-										materialsProperty.getPropertySetByID(Properties::RMHAO)
-									};
-
-									// Go over each material type
-									for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
-									{
-										// Check if an entry for the current material type was present within the properties
-										if(materialProperties[iMatType])
-										{
-											// Load the material data
-											materials[iMatType] = loadMaterialData(materialProperties[iMatType], newModelData.m_model.getMaterialArrays(), static_cast<MaterialType>(iMatType), meshDataIndex);
-										}
-									}
+						//ErrHandlerLoc::get().log(ErrorCode::Load_to_memory_success, ErrorSource::Source_ModelComponent, m_modelsProperties->m_models[modelIndex].m_modelName);
+					}
+				}
+			}
+		}
 
-									newModelData.m_meshes.push_back(MeshData(meshesInModelArray[iMesh], materials));
+		if(!m_texturesNeedLoading)
+		{
+			// Set the component as loaded, because the load function was called
+			setLoadedToMemory(true);
 
-									ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_ModelComponent, m_name + " - Model \'" + modelName + "\' imported");
-								}
-							}
-						}*/
-					}
-					/*else
-					{
-						// Get the material arrays that were loaded from the model file
-						auto &materialArrayFromModel = newModelData.m_model.getMaterialArrays();
+			if(m_modelsProperties != nullptr)
+			{
+				delete m_modelsProperties;
+				m_modelsProperties = nullptr;
+			}
+		}
+	}
 
-						// Iterate over every mesh in the model
-						for(decltype(meshesInModelArray.size()) iMesh = 0, numMeshes = meshesInModelArray.size(); iMesh < numMeshes; iMesh++)
-						{
-							// Define material data and material properties
-							MaterialData materials[MaterialType::MaterialType_NumOfTypes];
+	void loadModelsToMemory()
+	{
+		// Go over each model
+		for(decltype(m_modelData.size()) modelIndex = 0, modelSize = m_modelData.size(); modelIndex < modelSize; modelIndex++)
+		{
+			// Load the model to memory, to be able to access all of its meshes 
+			auto modelLoadError = m_modelData[modelIndex].m_model.loadToMemory();
 
-							// Go over each mesh in the model
-							//if(iMesh > materialArrayFromModel.m_numMaterials)
-							{
-								// Go over each material type
-								for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
-								{
-									// Get the texture filename and load it to memory
-									auto textureFromModel = Loaders::texture2D().load(materialArrayFromModel.m_materials[iMatType][iMesh].m_filename, static_cast<MaterialType>(iMatType), false);
-									auto materialLoadError = textureFromModel.loadToMemory();
+			if(modelLoadError == ErrorCode::Success)
+				ErrHandlerLoc::get().log(ErrorCode::Load_to_memory_success, ErrorSource::Source_ModelComponent, m_modelsProperties->m_models[modelIndex].m_modelName);
+			else
+				ErrHandlerLoc::get().log(ErrorCode::Load_to_memory_failure, ErrorSource::Source_ModelComponent, m_modelsProperties->m_models[modelIndex].m_modelName);
+		}
 
-									// Check if the texture was loaded successfully
-									if(materialLoadError == ErrorCode::Success)
-									{
-										materials[MaterialType::MaterialType_Diffuse].m_texture = textureFromModel;
-									}
-									else
-									{
-										ErrHandlerLoc::get().log(materialLoadError, ErrorSource::Source_Renderer);
-									}
-								}
+		resetModelsNeedsLoading();
 
-								// Add the data for this mesh. Include materials loaded from the model itself, if they were present, otherwise, include default textures instead
-								newModelData.m_meshes.push_back(MeshData(meshesInModelArray[iMesh], materials));
+		importTextures();
+		if(m_texturesNeedLoading)
+			loadTexturesToMemory();
+	}
 
-								ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_ModelComponent, m_name + " - Model \'" + modelName + "\' imported");
-							}
-						}
-					}*/
-				}
+	void loadTexturesToMemory()
+	{
+		// Go over each model
+		for(decltype(m_modelData.size()) modelIndex = 0, modelSize = m_modelData.size(); modelIndex < modelSize; modelIndex++)
+		{
+			// Get the material arrays that were loaded from the model file
+			auto &materialArrayFromModel = m_modelData[modelIndex].m_model.getMaterialArrays();
+
+			// Go over each mesh
+			for(decltype(m_modelData[modelIndex].m_meshes.size()) meshIndex = 0, meshSize = m_modelData[modelIndex].m_meshes.size(); meshIndex < meshSize; meshIndex++)
+			{
+				// Go over each material type
+				for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
+					m_modelData[modelIndex].m_meshes[meshIndex].m_materials[iMatType].m_texture.loadToMemory();
 			}
+		}
 
-			if(p_properties.getNumPropertySets() == 0)
-				ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_ModelComponent, m_name + " - missing model data");
+		// Set the component as loaded, because the load function was called
+		setLoadedToMemory(true);
+		resetModelsNeedsLoading();
+		resetTexturesNeedsLoading();
+
+		if(m_modelsProperties != nullptr)
+		{
+			delete m_modelsProperties;
+			m_modelsProperties = nullptr;
 		}
-		
-		return importError;
 	}
 
-	PropertySet exportObject()
-	{ 
-		return PropertySet(); 
+	BitMask getSystemType() { return Systems::Graphics; }
+
+	void update(const float p_deltaTime) { }
+
+	BitMask getDesiredSystemChanges() { return Systems::Changes::None; }
+
+	BitMask getPotentialSystemChanges() { return Systems::Changes::None; }
+
+	void changeOccurred(ObservedSubject *p_subject, BitMask p_changeType) { }
+
+	void receiveData(const DataType p_dataType, void *p_data, const bool p_deleteAfterReceiving = false)
+	{
+		switch(p_dataType)
+		{
+			case DataType_ModelsProperties:
+				{
+					if(m_modelsProperties != nullptr)
+						delete m_modelsProperties;
+
+					m_modelsProperties = new ModelsProperties(*static_cast<ModelsProperties*>(p_data));
+
+					m_loadPending = true;
+				}
+				break;
+		}
 	}
 
 	std::vector<LoadableObjectsContainer> getLoadableObjects()
@@ -442,12 +435,26 @@ public:
 	}
 
 	const inline std::vector<ModelData> &getModelData() const { return m_modelData; }
+	const inline bool getLoadPending() const { return m_loadPending; }
+	const inline bool getModelsNeedsLoading() const { return m_modelsNeedLoading; }
+	const inline bool getTexturesNeedsLoading() const { return m_texturesNeedLoading; }
 
-	inline void getMeshMaterialsProperties(MeshMaterialsProperties &p_modelsProperties) const
+	inline void getModelsProperties(ModelsProperties &p_modelsProperties) const
 	{
+		// Clear the models array if it's not empty
+		if(!p_modelsProperties.m_models.empty())
+			p_modelsProperties.m_models.clear();
+
 		// Go over each model
 		for(decltype(m_modelData.size()) modelSize = m_modelData.size(), modelIndex = 0; modelIndex < modelSize; modelIndex++)
 		{
+			// Add a new model entry
+			p_modelsProperties.m_models.push_back(MeshProperties());
+			auto &newModelEntry = p_modelsProperties.m_models.back();
+
+			// Add model filename to the models properties
+			newModelEntry.m_modelName = m_modelData[modelIndex].m_model.getFilename();
+
 			// Loop over each mesh
 			for(decltype(m_modelData[modelIndex].m_meshes.size()) meshSize = m_modelData[modelIndex].m_meshes.size(), meshIndex = 0; meshIndex < meshSize; meshIndex++)
 			{
@@ -459,37 +466,32 @@ public:
 				// Loop over each material
 				for(unsigned int materialIndex = 0; materialIndex < MaterialType::MaterialType_NumOfTypes; materialIndex++)
 				{
-					// Add texture filename only if the texture is not a default placeholder
-					if(Loaders::texture2D().isTextureDefault(m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_texture))
-						meshMaterials.push_back(std::string());
-					else
-					{
-						meshMaterials.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_texture.getFilename());
+					// Mark material as present if any of the textures are not default
+					if(!Loaders::texture2D().isTextureDefault(m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_texture))
 						materialPresent = true;
-					}
+
+					// Add texture filename
+					meshMaterials.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_texture.getFilename());
 
 					// Add texture scale
 					meshMaterialScales.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_materials[materialIndex].m_textureScale);
 				}
 
-				p_modelsProperties.m_meshMaterials.push_back(meshMaterials);
-				p_modelsProperties.m_meshMaterialsScale.push_back(meshMaterialScales);
-				p_modelsProperties.m_alphaThreshold.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_alphaThreshold);
-				p_modelsProperties.m_heightScale.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_heightScale);
-				p_modelsProperties.m_present.push_back(materialPresent);
-				p_modelsProperties.m_numOfMeshes++;
+				newModelEntry.m_meshMaterials.push_back(meshMaterials);
+				newModelEntry.m_meshMaterialsScale.push_back(meshMaterialScales);
+				newModelEntry.m_meshNames.push_back(m_modelData[modelIndex].m_model.getMeshName(meshIndex));
+				newModelEntry.m_alphaThreshold.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_alphaThreshold);
+				newModelEntry.m_emissiveIntensity.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_emissiveIntensity);
+				newModelEntry.m_heightScale.push_back(m_modelData[modelIndex].m_meshes[meshIndex].m_heightScale);
+				newModelEntry.m_present.push_back(materialPresent);
+				newModelEntry.m_numOfMeshes++;
 			}
 		}
 	}
-	inline void getModelsProperties(ModelsProperties &p_modelsProperties) const
-	{
-		// Go over each model
-		for(decltype(m_modelData.size()) modelSize = m_modelData.size(), modelIndex = 0; modelIndex < modelSize; modelIndex++)
-		{
-			// Add model filename to the models properties
-			p_modelsProperties.m_modelNames.emplace_back(m_modelData[modelIndex].m_model.getFilename());
-		}
-	}
+
+	const inline void resetLoadPending() { m_loadPending = false; }
+	const inline void resetModelsNeedsLoading() { m_modelsNeedLoading = false; }
+	const inline void resetTexturesNeedsLoading() { m_texturesNeedLoading = false; }
 
 private:
 	inline MaterialData loadMaterialData(PropertySet &p_materialProperty, Model::MaterialArrays &p_materialArraysFromModel, MaterialType p_materialType, std::size_t p_meshIndex)
@@ -561,8 +563,93 @@ private:
 		// Return the newly loaded material data
 		return newMaterialData;
 	}
+	inline void adjustMeshArraySizes()
+	{
+		// Go over each model
+		for(decltype(m_modelData.size()) modelIndex = 0, modelSize = m_modelData.size(); modelIndex < modelSize; modelIndex++)
+		{
+			auto numOfMeshes = m_modelData[modelIndex].m_model.getNumMeshes();
+
+			if(m_modelData[modelIndex].m_meshes.size() != numOfMeshes)
+			{
+				if(m_modelData[modelIndex].m_meshes.size() > numOfMeshes)
+				{
+					while(m_modelData[modelIndex].m_meshes.size() != numOfMeshes)
+						m_modelData[modelIndex].m_meshes.pop_back();
+				}
+				else
+				{
+					//while(m_modelData[modelIndex].m_meshes.size() != numOfMeshes)
+					//{
+					//	auto meshIndex = m_modelData[modelIndex].m_meshes.size();
+
+					//	if(m_modelsProperties->m_models[modelIndex].m_meshMaterials.size() > meshIndex)
+					//	{
+					//		if(m_modelsProperties->m_models[modelIndex].m_present[meshIndex] == true)
+					//		{
+					//			// Define material data and material properties
+					//			MaterialData materials[MaterialType::MaterialType_NumOfTypes];
+
+					//			// Go over each material type
+					//			for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
+					//			{
+					//				auto filename = materialArrayFromModel.m_materials[iMatType][meshIndex].m_filename;
+
+					//				if(!m_modelsProperties->m_models[modelIndex].m_meshMaterials[meshIndex][iMatType].empty())
+					//				{
+					//					filename = m_modelsProperties->m_models[modelIndex].m_meshMaterials[meshIndex][iMatType];
+					//				}
+
+					//				materials[iMatType].m_texture = Loaders::texture2D().load(filename, static_cast<MaterialType>(iMatType), false);
+
+					//				if(!materials[iMatType].m_texture.isLoadedToMemory())
+					//					m_texturesNeedLoading = true;
+
+					//				materials[iMatType].m_textureScale = m_modelsProperties->m_models[modelIndex].m_meshMaterialsScale[meshIndex][iMatType];
+					//			}
+
+					//			// Add the data for this mesh. Include materials loaded from the model itself, if they were present, otherwise, include default textures instead
+					//			newModelData.m_meshes.push_back(MeshData(
+					//				newModelData.m_model.getMeshArray()[meshIndex],
+					//				materials,
+					//				m_modelsProperties->m_models[modelIndex].m_heightScale[meshIndex],
+					//				m_modelsProperties->m_models[modelIndex].m_alphaThreshold[meshIndex],
+					//				m_modelsProperties->m_models[modelIndex].m_emissiveIntensity[meshIndex]));
+
+					//		}
+					//	}
+					//	else
+					//	{
+					//		// Define material data and material properties
+					//		MaterialData materials[MaterialType::MaterialType_NumOfTypes];
+
+					//		// Go over each material type
+					//		for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
+					//		{
+					//			auto filename = materialArrayFromModel.m_materials[iMatType][meshIndex].m_filename;
+
+					//			materials[iMatType].m_texture = Loaders::texture2D().load(filename, static_cast<MaterialType>(iMatType), false);
+
+					//			if(!materials[iMatType].m_texture.isLoadedToMemory())
+					//				m_texturesNeedLoading = true;
+
+					//			materials[iMatType].m_textureScale = glm::vec2(Config::graphicsVar().texture_tiling_factor, Config::graphicsVar().texture_tiling_factor);
+					//		}
+
+					//		newModelData.m_meshes.push_back(MeshData(newModelData.m_model.getMeshArray()[meshIndex], materials, Config::graphicsVar().height_scale, Config::graphicsVar().alpha_threshold, Config::graphicsVar().emissive_multiplier));
+
+					//	}
+					//}
+				}
+			}
+		}
+	}
 
 	std::vector<ModelData> m_modelData;
-	MeshMaterialsProperties *m_materialsFromProperties;
 	ModelsProperties *m_modelsProperties;
+
+	bool m_modelsNeedLoading;
+	bool m_texturesNeedLoading;
+
+	bool m_loadPending;
 };

+ 5 - 2
Praxis3D/Source/ModelLoader.cpp

@@ -125,6 +125,7 @@ ErrorCode Model::loadFromScene(const aiScene &p_assimpScene)
 
 	// Reserve space in the vectors for every mesh
 	m_meshPool.resize(p_assimpScene.mNumMeshes);
+	m_meshNames.resize(p_assimpScene.mNumMeshes);
 	m_numMeshes = p_assimpScene.mNumMeshes;
 
 	unsigned int numIndicesTotal = 0;
@@ -173,6 +174,9 @@ ErrorCode Model::loadMeshes(const aiScene &p_assimpScene)
 
 	for(size_t meshIndex = 0, verticeIndex = 0, indicesIndex = 0; meshIndex < p_assimpScene.mNumMeshes; meshIndex++)
 	{
+		// Set the mesh name
+		m_meshNames[meshIndex] = p_assimpScene.mMeshes[meshIndex]->mName.C_Str();
+
 		// Make sure that the texture coordinates array exist (by checking if the first member of the array does)
 		bool textureCoordsExist = p_assimpScene.mMeshes[meshIndex]->mTextureCoords[0] ? true : false;
 
@@ -264,8 +268,7 @@ ErrorCode Model::loadMeshes(const aiScene &p_assimpScene)
 			{
 				m_indices[indicesIndex] = p_assimpScene.mMeshes[meshIndex]->mFaces[i].mIndices[0];
 				m_indices[indicesIndex + 1] = p_assimpScene.mMeshes[meshIndex]->mFaces[i].mIndices[1];
-				m_indices[indicesIndex + 2] = 
-					p_assimpScene.mMeshes[meshIndex]->mFaces[i].mIndices[2];
+				m_indices[indicesIndex + 2] = p_assimpScene.mMeshes[meshIndex]->mFaces[i].mIndices[2];
 
 				indicesIndex += 3;
 			}

+ 11 - 0
Praxis3D/Source/ModelLoader.h

@@ -94,6 +94,9 @@ public:
 
 		for(int i = 0; i < ModelBuffer_NumAllTypes; i++)
 			m_buffers[i] = 0;
+
+		for(int i = 0; i < ModelBuffer_NumAllTypes; i++)
+			m_bufferSize[i] = 0;
 	}
 
 	// Loads data from HDD to RAM and restructures it to be used to fill buffers later
@@ -135,6 +138,7 @@ public:
 	int64_t m_bufferSize[ModelBuffer_NumAllTypes];
 
 	std::vector<Mesh> m_meshPool;
+	std::vector<std::string> m_meshNames;
 	
 	std::vector<unsigned int> m_indices;
 	std::vector<glm::vec3> m_positions;
@@ -263,6 +267,13 @@ public:
 		inline std::string getFilename() const						{ return m_model->m_filename;				}
 		inline const bool isLoadedToMemory() const					{ return m_model->isLoadedToMemory();		}
 		inline const bool isLoadedToVideoMemory() const				{ return m_model->isLoadedToVideoMemory();	}
+		inline std::string getMeshName(size_t p_meshIndex) const
+		{
+			if(p_meshIndex < m_model->m_meshNames.size())
+				return m_model->m_meshNames[p_meshIndex];
+
+			return std::string();
+		}
 
 	private:
 		ModelHandle(Model &p_model) : m_model(&p_model) { m_model->incRefCounter(); }

+ 0 - 1
Praxis3D/Source/RendererBackend.cpp

@@ -72,7 +72,6 @@ void RendererBackend::processDrawing(const DrawCommands &p_drawCommands, const U
 	{
 		// Get uniform data
 		const UniformObjectData &uniformObjectData = p_drawCommands[i].second.m_uniformObjectData;
-		//UniformData uniformData(p_drawCommands[i].second.m_uniformObjectData, p_frameData);
 
 		// Get various handles
 		const auto shaderHandle = p_drawCommands[i].second.m_shaderHandle;

+ 1 - 9
Praxis3D/Source/RendererFrontend.h

@@ -77,14 +77,6 @@ protected:
 		// Calculate model-view-projection matrix
 		const glm::mat4 modelViewProjMatrix = p_viewProjMatrix * p_modelMatrix;
 
-		// Unused for now
-		//unsigned int materials[MaterialType_NumOfTypes];
-
-		//for(decltype(p_modelData.m_materials[0].size()) i = 0; i < MaterialType_NumOfTypes; i++)
-		//{
-			//materials[i] = p_object.m_materials[i]
-		//}
-
 		// Calculate the sort key
 		RendererBackend::DrawCommands::value_type::first_type sortKey = 0;
 		
@@ -97,7 +89,7 @@ protected:
 				modelViewProjMatrix,
 				p_modelData.m_meshes[meshIndex].m_heightScale,
 				p_modelData.m_meshes[meshIndex].m_alphaThreshold,
-				p_modelData.m_meshes[meshIndex].m_alphaThreshold,
+				p_modelData.m_meshes[meshIndex].m_emissiveIntensity,
 				p_modelData.m_meshes[meshIndex].m_materials[MaterialType::MaterialType_Diffuse].m_textureScale.x);
 
 			m_drawCommands.emplace_back(

+ 61 - 42
Praxis3D/Source/RendererScene.cpp

@@ -184,6 +184,62 @@ void RendererScene::update(const float p_deltaTime)
 	// Get the entity registry 
 	auto &entityRegistry = worldScene->getEntityRegistry();
 
+	//	 _______________________________
+	//	|							    |
+	//	|	 CHECK FOR LOAD PENDING		|
+	//	|_______________________________|
+	//
+	// Go over each not-loading components and check whether they have anything that needs to be loaded
+	auto modelNoLoadView = entityRegistry.view<ModelComponent, SpatialComponent>(entt::exclude<ShaderComponent, GraphicsLoadToMemoryComponent, GraphicsLoadToVideoMemoryComponent>);
+	for(auto entity : modelNoLoadView)
+	{
+		// Get the component
+		auto &component = modelNoLoadView.get<ModelComponent>(entity);
+
+		// Check if there is anything that needs to be loaded
+		if(component.getLoadPending())
+		{
+			component.importModels();
+			if(!component.getModelsNeedsLoading())
+			{
+				component.importTextures();
+				if(!component.getTexturesNeedsLoading())
+				{
+					// Reset load pending flag
+					component.resetLoadPending();
+					component.setLoadedToMemory(true);
+					component.setLoadedToVideoMemory(true);
+				}
+				else
+				{
+					// Add load to memory component, to mark the entity as loading
+					worldScene->addComponent<GraphicsLoadToMemoryComponent>(entity, entity);
+
+					// Reset load pending flag
+					component.resetLoadPending();
+					component.setLoadedToMemory(false);
+					component.setLoadedToVideoMemory(false);
+
+					// Start loading the component to memory in the background
+					TaskManagerLocator::get().startBackgroundThread(std::bind(&ModelComponent::loadTexturesToMemory, &component));
+				}
+			}
+			else
+			{
+				// Add load to memory component, to mark the entity as loading
+				worldScene->addComponent<GraphicsLoadToMemoryComponent>(entity, entity);
+
+				// Reset load pending flag
+				component.resetLoadPending();
+				component.setLoadedToMemory(false);
+				component.setLoadedToVideoMemory(false);
+
+				// Start loading the component to memory in the background
+				TaskManagerLocator::get().startBackgroundThread(std::bind(&ModelComponent::loadModelsToMemory, &component));
+			}
+		}
+	}
+
 	//	 _______________________________
 	//	|							    |
 	//	| CURRENTLY LOADING COMPONENTS	|
@@ -218,42 +274,6 @@ void RendererScene::update(const float p_deltaTime)
 	//	|		   TO MEMORY			|
 	//	|_______________________________|
 	//
-	// Check the entities that are being loaded to memory
-	// If they have already been loaded, remove the load-to-memory component and add the load-to-video-memory component, so they can be loaded to GPU in the renderer
-	/*auto modelAndLoadView = entityRegistry.view<ModelComponent, GraphicsLoadToMemoryComponent>(entt::exclude<ShaderComponent>);
-	for(auto entity : modelAndLoadView)
-	{
-		auto &modelComponent = modelAndLoadView.get<ModelComponent>(entity);
-
-		// Perform a check that marks an object if it is loaded to memory
-		modelComponent.performCheckIsLoadedToMemory();
-
-		// If the object has loaded to memory already, add to load queue
-		if(modelComponent.isLoadedToMemory())
-		{
-			// Remove the load-to-memory component, signifying that it has already been loaded to memory
-			worldScene->removeComponent<GraphicsLoadToMemoryComponent>(entity);
-
-			// Make the component active, so it is processed in the renderer
-			modelComponent.setActive(modelComponent.m_setActiveAfterLoading);
-
-			// Do not add the load-to-video-memory component if the object is already loaded to GPU
-			modelComponent.performCheckIsLoadedToVideoMemory();
-			if(!modelComponent.isLoadedToVideoMemory())
-			{
-				auto &loadToVideoMemoryComponent = worldScene->addComponent<GraphicsLoadToVideoMemoryComponent>(entity, entity);
-
-				// Get all loadable objects from the model component
-				auto loadableObjectsFromModel = modelComponent.getLoadableObjects();
-
-				// Iterate over all loadable objects from the model component, and if any of them are not loaded to video memory already, add them to the to-load list
-				for(decltype(loadableObjectsFromModel.size()) size = loadableObjectsFromModel.size(), i = 0; i < size; i++)
-					if(!loadableObjectsFromModel[i].isLoadedToVideoMemory())
-						loadToVideoMemoryComponent.m_objectsToLoad.emplace(loadableObjectsFromModel[i]);
-			}
-		}
-	}*/
-
 	// Check the entities that are being loaded to memory
 	// If they have already been loaded, remove the load-to-memory component and add the load-to-video-memory component, so they can be loaded to GPU in the renderer
 	auto modelAndLoadView = entityRegistry.view<ModelComponent, GraphicsLoadToMemoryComponent>();
@@ -527,7 +547,7 @@ SystemObject *RendererScene::createComponent(const EntityID &p_entityID, const L
 				component.m_lightComponent.m_directional.m_intensity = p_constructionInfo.m_intensity;
 				component.setLoadedToMemory(true);
 
-				ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, p_constructionInfo.m_name + " - Directional light loaded");
+				ErrHandlerLoc().get().log(ErrorCode::Load_success, ErrorSource::Source_LightComponent, p_constructionInfo.m_name);
 				break;
 
 			case LightComponent::LightComponentType::LightComponentType_point:
@@ -537,7 +557,7 @@ SystemObject *RendererScene::createComponent(const EntityID &p_entityID, const L
 				component.m_lightComponent.m_point.m_intensity = p_constructionInfo.m_intensity;
 				component.setLoadedToMemory(true);
 
-				ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, p_constructionInfo.m_name + " - Point light loaded");
+				ErrHandlerLoc().get().log(ErrorCode::Load_success, ErrorSource::Source_LightComponent, p_constructionInfo.m_name);
 				break;
 
 			case LightComponent::LightComponentType::LightComponentType_spot:
@@ -548,12 +568,12 @@ SystemObject *RendererScene::createComponent(const EntityID &p_entityID, const L
 				component.m_lightComponent.m_spot.m_intensity = p_constructionInfo.m_intensity;
 				component.setLoadedToMemory(true);
 
-				ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_LightComponent, p_constructionInfo.m_name + " - Spot light loaded");
+				ErrHandlerLoc().get().log(ErrorCode::Load_success, ErrorSource::Source_LightComponent, p_constructionInfo.m_name);
 				break;
 
 			case LightComponent::LightComponentType::LightComponentType_null:
 			default:
-				ErrHandlerLoc().get().log(ErrorType::Warning, ErrorSource::Source_LightComponent, p_constructionInfo.m_name + " - missing \'Type\' identifier");
+				ErrHandlerLoc().get().log(ErrorCode::Property_missing_type, ErrorSource::Source_LightComponent, p_constructionInfo.m_name);
 				worldScene->removeComponent<LightComponent>(p_entityID);
 				break;
 			}
@@ -576,7 +596,7 @@ SystemObject *RendererScene::createComponent(const EntityID &p_entityID, const M
 	SystemObject *returnObject = g_nullSystemBase.getScene(EngineStateType::EngineStateType_Default)->getNullObject();
 
 	// Make sure there are models present
-	if(!p_constructionInfo.m_modelsProperties.m_modelNames.empty())
+	if(!p_constructionInfo.m_modelsProperties.m_models.empty())
 	{
 		// Get the world scene required for attaching components to the entity
 		WorldScene *worldScene = static_cast<WorldScene *>(m_sceneLoader->getSystemScene(Systems::World));
@@ -591,7 +611,6 @@ SystemObject *RendererScene::createComponent(const EntityID &p_entityID, const M
 			component.setActive(false);
 
 			component.m_modelsProperties = new ModelComponent::ModelsProperties(p_constructionInfo.m_modelsProperties);
-			component.m_materialsFromProperties = new ModelComponent::MeshMaterialsProperties(p_constructionInfo.m_materialsFromProperties);
 
 			// Add the load-to-memory component signifying that it is currently being loaded to memory
 			//m_componentsLoadingToMemory.emplace_back(component);

+ 0 - 1
Praxis3D/Source/RendererScene.h

@@ -187,7 +187,6 @@ public:
 		p_constructionInfo.m_active = p_component.isObjectActive();
 		p_constructionInfo.m_name = p_component.getName();
 
-		p_component.getMeshMaterialsProperties(p_constructionInfo.m_materialsFromProperties);
 		p_component.getModelsProperties(p_constructionInfo.m_modelsProperties);
 	}
 	void exportComponent(ShaderComponent::ShaderComponentConstructionInfo &p_constructionInfo, const ShaderComponent &p_component)

+ 136 - 105
Praxis3D/Source/SceneLoader.cpp

@@ -612,6 +612,7 @@ void SceneLoader::importFromProperties(GraphicsComponentsConstructionInfo &p_con
 				default:
 
 					ErrHandlerLoc().get().log(ErrorType::Warning, ErrorSource::Source_LightComponent, p_name + " - missing \'Type\' identifier");
+
 					delete p_constructionInfo.m_lightConstructionInfo;
 					p_constructionInfo.m_lightConstructionInfo = nullptr;
 
@@ -627,6 +628,8 @@ void SceneLoader::importFromProperties(GraphicsComponentsConstructionInfo &p_con
 
 				p_constructionInfo.m_modelConstructionInfo->m_name = p_name + Config::componentVar().component_name_separator + GetString(Properties::PropertyID::ModelComponent);
 
+				bool modelDataPresent = false;
+
 				auto &modelsProperty = p_properties.getPropertySetByID(Properties::Models);
 
 				if(modelsProperty)
@@ -637,76 +640,92 @@ void SceneLoader::importFromProperties(GraphicsComponentsConstructionInfo &p_con
 						// Get model filename
 						auto modelName = modelsProperty.getPropertySet(iModel).getPropertyByID(Properties::Filename).getString();
 
-						// Add a new model data entry, and get a reference to it
-						p_constructionInfo.m_modelConstructionInfo->m_modelsProperties.m_modelNames.push_back(modelName);
+						// Continue only of the model filename is not empty
+						if(!modelName.empty())
+						{
+							modelDataPresent = true;
 
-						auto &meshesProperty = modelsProperty.getPropertySet(iModel).getPropertySetByID(Properties::Meshes);
+							// Add a new model data entry, and get a reference to it
+							p_constructionInfo.m_modelConstructionInfo->m_modelsProperties.m_models.push_back(ModelComponent::MeshProperties());
+							auto &newModelEntry = p_constructionInfo.m_modelConstructionInfo->m_modelsProperties.m_models.back();
 
-						// Check if the meshes array node is present;
-						// If it is present, only add the meshes included in the meshes node
-						// If it is not present, add all the meshes included in the model
-						if(meshesProperty)
-						{
-							if(meshesProperty.getNumPropertySets() > 0)
+							// Assign the model filename
+							newModelEntry.m_modelName = modelName;
+
+							// Get meshes property
+							auto &meshesProperty = modelsProperty.getPropertySet(iModel).getPropertySetByID(Properties::Meshes);
+
+							// Check if the meshes array node is present;
+							// If it is present, only add the meshes included in the meshes node
+							// If it is not present, add all the meshes included in the model
+							if(meshesProperty)
 							{
-								// Loop over each mesh entry in the model node
-								for(decltype(meshesProperty.getNumPropertySets()) iMesh = 0, numMeshes = meshesProperty.getNumPropertySets(); iMesh < numMeshes; iMesh++)
+								if(meshesProperty.getNumPropertySets() > 0)
 								{
-									// Try to get the mesh index property node and check if it is present
-									auto &meshIndexProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::Index);
-									if(meshIndexProperty)
+									// Loop over each mesh entry in the model node
+									for(decltype(meshesProperty.getNumPropertySets()) iMesh = 0, numMeshes = meshesProperty.getNumPropertySets(); iMesh < numMeshes; iMesh++)
 									{
-										// Get the mesh index, check if it is valid and within the range of mesh array that was loaded from the model
-										const int meshDataIndex = meshIndexProperty.getInt();
-
-										// Make sure the meshMaterials vector can fit the given mesh index
-										if(meshDataIndex >= p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterials.size())
+										// Try to get the mesh index property node and check if it is present
+										auto &meshIndexProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::Index);
+										if(meshIndexProperty)
 										{
-											p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.resize(meshDataIndex + 1);
-											p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_present[meshDataIndex] = true;
-										}
+											// Get the mesh index, check if it is valid and within the range of mesh array that was loaded from the model
+											const int meshDataIndex = meshIndexProperty.getInt();
+
+											// Make sure the meshMaterials vector can fit the given mesh index
+											if(meshDataIndex >= newModelEntry.m_meshMaterials.size())
+											{
+												newModelEntry.resize(meshDataIndex + 1);
+												newModelEntry.m_present[meshDataIndex] = true;
+											}
 
-										// Get material alpha threshold value, if it is present
-										auto alphaThresholdProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::AlphaThreshold);
-										if(alphaThresholdProperty)
-											p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_alphaThreshold[meshDataIndex] = alphaThresholdProperty.getFloat();
+											// Get material alpha threshold value, if it is present
+											auto alphaThresholdProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::AlphaThreshold);
+											if(alphaThresholdProperty)
+												newModelEntry.m_alphaThreshold[meshDataIndex] = alphaThresholdProperty.getFloat();
 
-										// Get material height scale value, if it is present
-										auto heightScaleProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::HeightScale);
-										if(heightScaleProperty)
-											p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_heightScale[meshDataIndex] = heightScaleProperty.getFloat();
+											// Get emissive intensity, if it is present
+											auto emissiveIntensityProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::EmissiveIntensity);
+											if(emissiveIntensityProperty)
+												newModelEntry.m_emissiveIntensity[meshDataIndex] = emissiveIntensityProperty.getFloat();
 
-										// Get material properties
-										auto materialsProperty = meshesProperty.getPropertySet(iMesh).getPropertySetByID(Properties::Materials);
+											// Get material height scale value, if it is present
+											auto heightScaleProperty = meshesProperty.getPropertySet(iMesh).getPropertyByID(Properties::HeightScale);
+											if(heightScaleProperty)
+												newModelEntry.m_heightScale[meshDataIndex] = heightScaleProperty.getFloat();
 
-										// Define material data and material properties
-										MaterialData materials[MaterialType::MaterialType_NumOfTypes];
-										PropertySet materialProperties[MaterialType::MaterialType_NumOfTypes] =
-										{
-											materialsProperty.getPropertySetByID(Properties::Diffuse),
-											materialsProperty.getPropertySetByID(Properties::Normal),
-											materialsProperty.getPropertySetByID(Properties::Emissive),
-											materialsProperty.getPropertySetByID(Properties::RMHAO)
-										};
-
-										// Go over each material type
-										for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
-										{
-											// Check if an entry for the current material type was present within the properties
-											if(materialProperties[iMatType])
+											// Get material properties
+											auto materialsProperty = meshesProperty.getPropertySet(iMesh).getPropertySetByID(Properties::Materials);
+
+											// Define material data and material properties
+											MaterialData materials[MaterialType::MaterialType_NumOfTypes];
+											PropertySet materialProperties[MaterialType::MaterialType_NumOfTypes] =
 											{
-												// Get texture filename property, check if it is valid
-												auto filenameProperty = materialProperties[iMatType].getPropertyByID(Properties::Filename);
-												if(filenameProperty.isVariableTypeString())
+												materialsProperty.getPropertySetByID(Properties::Diffuse),
+												materialsProperty.getPropertySetByID(Properties::Normal),
+												materialsProperty.getPropertySetByID(Properties::Emissive),
+												materialsProperty.getPropertySetByID(Properties::RMHAO)
+											};
+
+											// Go over each material type
+											for(unsigned int iMatType = 0; iMatType < MaterialType::MaterialType_NumOfTypes; iMatType++)
+											{
+												// Check if an entry for the current material type was present within the properties
+												if(materialProperties[iMatType])
 												{
-													// Get texture filename string, check if it is valid
-													p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterials[meshDataIndex][iMatType] = filenameProperty.getString();
+													// Get texture filename property, check if it is valid
+													auto filenameProperty = materialProperties[iMatType].getPropertyByID(Properties::Filename);
+													if(filenameProperty.isVariableTypeString())
+													{
+														// Get texture filename string, check if it is valid
+														newModelEntry.m_meshMaterials[meshDataIndex][iMatType] = filenameProperty.getString();
+													}
+
+													// Get texture scale property, check if it is valid
+													auto scaleProperty = materialProperties[iMatType].getPropertyByID(Properties::TextureScale);
+													if(scaleProperty)
+														newModelEntry.m_meshMaterialsScale[meshDataIndex][iMatType] = scaleProperty.getVec2f();
 												}
-
-												// Get texture scale property, check if it is valid
-												auto scaleProperty = materialProperties[iMatType].getPropertyByID(Properties::TextureScale);
-												if(scaleProperty)
-													p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterialsScale[meshDataIndex][iMatType] = scaleProperty.getVec2f();
 											}
 										}
 									}
@@ -716,8 +735,13 @@ void SceneLoader::importFromProperties(GraphicsComponentsConstructionInfo &p_con
 					}
 				}
 
-				if(p_properties.getNumPropertySets() == 0)
+				if(p_properties.getNumPropertySets() == 0 || !modelDataPresent)
+				{
 					ErrHandlerLoc().get().log(ErrorType::Info, ErrorSource::Source_ModelComponent, p_name + " - missing model data");
+
+					delete p_constructionInfo.m_modelConstructionInfo;
+					p_constructionInfo.m_modelConstructionInfo = nullptr;
+				}
 			}
 			break;
 
@@ -1143,69 +1167,76 @@ void SceneLoader::exportToProperties(const GraphicsComponentsConstructionInfo &p
 			auto &modelsPropertySet = componentPropertySet.addPropertySet(Properties::PropertyID::Models);
 
 			// Go over each model
-			for(auto &model : p_constructionInfo.m_modelConstructionInfo->m_modelsProperties.m_modelNames)
+			for(auto &model : p_constructionInfo.m_modelConstructionInfo->m_modelsProperties.m_models)
 			{
-				auto &modelPropertyArrayEntry = modelsPropertySet.addPropertySet(Properties::ArrayEntry);
+				// Make sure the number of meshes is not bigger than any of the property arrays
+				if(	model.m_numOfMeshes <= model.m_meshMaterials.size() &&
+					model.m_numOfMeshes <= model.m_meshMaterialsScale.size() &&
+					model.m_numOfMeshes <= model.m_alphaThreshold.size() &&
+					model.m_numOfMeshes <= model.m_heightScale.size() &&
+					model.m_numOfMeshes <= model.m_present.size())
+				{
+					auto &modelPropertyArrayEntry = modelsPropertySet.addPropertySet(Properties::ArrayEntry);
 
-				// Add model data
-				modelPropertyArrayEntry.addProperty(Properties::PropertyID::Filename, model);
+					// Add model data
+					modelPropertyArrayEntry.addProperty(Properties::PropertyID::Filename, model.m_modelName);
 
-				auto &meshesPropertySet = modelPropertyArrayEntry.addPropertySet(Properties::PropertyID::Meshes);
+					auto &meshesPropertySet = modelPropertyArrayEntry.addPropertySet(Properties::PropertyID::Meshes);
 
-				// Go over each mesh
-				for(decltype(p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_numOfMeshes) i = 0; i < p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_numOfMeshes; i++)
-				{
-					// Make sure the mesh data is present
-					if(p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_present[i])
+					// Go over each mesh
+					for(decltype(model.m_numOfMeshes) i = 0; i < model.m_numOfMeshes; i++)
 					{
-						auto &meshPropertyArrayEntry = meshesPropertySet.addPropertySet(Properties::ArrayEntry);
+						// Make sure the mesh data is present
+						if(model.m_present[i])
+						{
+							auto &meshPropertyArrayEntry = meshesPropertySet.addPropertySet(Properties::ArrayEntry);
 
-						// Add mesh data
-						meshPropertyArrayEntry.addProperty(Properties::PropertyID::Index, (int)i);
-						meshPropertyArrayEntry.addProperty(Properties::PropertyID::AlphaThreshold, p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_alphaThreshold[i]);
-						meshPropertyArrayEntry.addProperty(Properties::PropertyID::HeightScale, p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_heightScale[i]);
+							// Add mesh data
+							meshPropertyArrayEntry.addProperty(Properties::PropertyID::Index, (int)i);
+							meshPropertyArrayEntry.addProperty(Properties::PropertyID::AlphaThreshold, model.m_alphaThreshold[i]);
+							meshPropertyArrayEntry.addProperty(Properties::PropertyID::HeightScale, model.m_heightScale[i]);
 
-						auto &materialsPropertySet = meshPropertyArrayEntry.addPropertySet(Properties::Materials);
+							auto &materialsPropertySet = meshPropertyArrayEntry.addPropertySet(Properties::Materials);
 
-						// Go over each material
-						for(unsigned int materialType = 0; materialType < MaterialType::MaterialType_NumOfTypes; materialType++)
-						{
-							// Make sure the material filename is not empty
-							if(!p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterials[i][materialType].empty())
+							// Go over each material
+							for(unsigned int materialType = 0; materialType < MaterialType::MaterialType_NumOfTypes; materialType++)
 							{
-								Properties::PropertyID materialPropertyID = Properties::Null;
-
-								// Convert MaterialType to PropertyID
-								switch(materialType)
+								// Make sure the material filename is not empty
+								if(!model.m_meshMaterials[i][materialType].empty())
 								{
-									case MaterialType_Diffuse:
-										materialPropertyID = Properties::Diffuse;
-										break;
-									case MaterialType_Normal:
-										materialPropertyID = Properties::Normal;
-										break;
-									case MaterialType_Emissive:
-										materialPropertyID = Properties::Emissive;
-										break;
-									case MaterialType_Combined:
-										materialPropertyID = Properties::RMHAO;
-										break;
-								}
-								auto &materialPropertySet = materialsPropertySet.addPropertySet(materialPropertyID);
+									Properties::PropertyID materialPropertyID = Properties::Null;
+
+									// Convert MaterialType to PropertyID
+									switch(materialType)
+									{
+										case MaterialType_Diffuse:
+											materialPropertyID = Properties::Diffuse;
+											break;
+										case MaterialType_Normal:
+											materialPropertyID = Properties::Normal;
+											break;
+										case MaterialType_Emissive:
+											materialPropertyID = Properties::Emissive;
+											break;
+										case MaterialType_Combined:
+											materialPropertyID = Properties::RMHAO;
+											break;
+									}
+									auto &materialPropertySet = materialsPropertySet.addPropertySet(materialPropertyID);
 
-								// Add material data
-								materialPropertySet.addProperty(Properties::PropertyID::Filename, p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterials[i][materialType]);
-								materialPropertySet.addProperty(Properties::PropertyID::TextureScale, p_constructionInfo.m_modelConstructionInfo->m_materialsFromProperties.m_meshMaterialsScale[i][materialType]);
+									// Add material data
+									materialPropertySet.addProperty(Properties::PropertyID::Filename, model.m_meshMaterials[i][materialType]);
+									materialPropertySet.addProperty(Properties::PropertyID::TextureScale, model.m_meshMaterialsScale[i][materialType]);
+								}
 							}
 						}
 					}
 				}
-
-
-
+				else
+				{
+					ErrHandlerLoc::get().log(ErrorCode::Number_of_meshes_missmatch, ErrorSource::Source_SceneLoader, model.m_modelName);
+				}
 			}
-
-			modelsPropertySet.addPropertySet(Properties::ArrayEntry);
 		}
 
 		// Export ShaderComponent

+ 1 - 1
Praxis3D/Source/ScriptScene.cpp

@@ -236,7 +236,7 @@ void ScriptScene::changeOccurred(ObservedSubject *p_subject, BitMask p_changeTyp
 {
 }
 
-void ScriptScene::receiveData(const DataType p_dataType, void *p_data, const bool p_deleteAfterReceiving)
+void ScriptScene::receiveData(const DataType p_dataType, void *p_data, const bool p_deleteAfterReceiving = false)
 {
 	switch(p_dataType)
 	{

+ 5 - 5
Praxis3D/Source/ShaderUniforms.h

@@ -330,10 +330,10 @@ public:
 
 	void update(const UniformData &p_uniformData)
 	{
-		// Check if the same value is not already assigned (a small optimization)
-		if(m_currentEmissiveMultiplier != Config::graphicsVar().emissive_multiplier)
+		// Check if the same value is not already assigned (a small optimization)		
+		if(m_currentEmissiveMultiplier != p_uniformData.m_objectData.m_emissiveIntensity)
 		{
-			m_currentEmissiveMultiplier = Config::graphicsVar().emissive_multiplier;
+			m_currentEmissiveMultiplier = p_uniformData.m_objectData.m_emissiveIntensity;
 
 			glUniform1f(m_uniformHandle, m_currentEmissiveMultiplier);
 		}
@@ -350,9 +350,9 @@ public:
 	void update(const UniformData &p_uniformData)
 	{
 		// Check if the same value is not already assigned (a small optimization)
-		if(m_currentEmissiveThreshold != p_uniformData.m_objectData.m_emissiveThreshold)
+		if(m_currentEmissiveThreshold != Config::graphicsVar().emissive_threshold)
 		{
-			m_currentEmissiveThreshold = p_uniformData.m_objectData.m_emissiveThreshold;
+			m_currentEmissiveThreshold = Config::graphicsVar().emissive_threshold;
 
 			glUniform1f(m_uniformHandle, m_currentEmissiveThreshold);
 		}

+ 7 - 0
Praxis3D/Source/TextureLoader.h

@@ -60,10 +60,14 @@ public:
 	inline int getMipmapLevel()						const { return m_mipmapLevel; }
 	inline const unsigned char *getPixelData()		const { return m_pixelData; }
 
+	// Returns true of the texture was loaded from file
+	const inline bool isLoadedFromFile() const { return m_loadedFromFile; }
+
 protected:
 	Texture2D(LoaderBase<TextureLoader2D, Texture2D> *p_loaderBase, std::string p_filename, size_t p_uniqueID, unsigned int p_handle) : UniqueObject(p_loaderBase, p_uniqueID, p_filename), m_handle(p_handle)
 	{
 		m_size = 0;
+		m_loadedFromFile = false;
 		m_enableMipmap = Config::textureVar().generate_mipmaps;
 		m_mipmapLevel = 0;
 		m_textureWidth = 0;
@@ -137,6 +141,7 @@ protected:
 				}
 
 				setLoadedToMemory(true);
+				m_loadedFromFile = true;
 			}
 			else
 			{
@@ -214,6 +219,7 @@ protected:
 	TextureFormat m_textureFormat;
 	TextureDataFormat m_textureDataFormat;
 	TextureDataType m_textureDataType;
+	bool m_loadedFromFile;
 	bool m_enableMipmap;
 	int m_mipmapLevel;
 
@@ -290,6 +296,7 @@ public:
 		inline TextureDataType getTextureDataType() const { return m_textureData->m_textureDataType; }
 		inline bool getEnableMipmap() const { return m_textureData->m_enableMipmap; }
 		inline const unsigned char *getPixelData() const { return m_textureData->m_pixelData; }
+		const inline bool isLoadedFromFile() const { return m_textureData->m_loadedFromFile; }
 
 	private:
 		// Increment the reference counter when creating a handle

+ 4 - 9
Praxis3D/Source/UniformData.h

@@ -53,27 +53,24 @@ struct UniformObjectData
 	{
 		m_heightScale = 0.0f;
 		m_alphaThreshold = 0.0f;
-		m_emissiveThreshold = 0.0f;
+		m_emissiveIntensity = 0.0f;
 		m_textureTilingFactor = 1.0f;
 	}
 
 	UniformObjectData(const glm::mat4 &p_modelMat,
 					  const glm::mat4 &p_modelViewProjMatrix,
-					  //const unsigned int (&p_materials)[MaterialType_NumOfTypes],
 					  float	p_heightScale = 0.0f,
 					  float p_alphaThreshold = 0.0f,
-					  float p_emissiveThreshold = 0.0f,
+					  float p_emissiveIntensity = 0.0f,
 					  float p_textureTilingFactor = 1.0f)
 	{
 		m_heightScale = p_heightScale;
 		m_alphaThreshold = p_alphaThreshold;
-		m_emissiveThreshold = p_emissiveThreshold;
+		m_emissiveIntensity = p_emissiveIntensity;
 		m_textureTilingFactor = p_textureTilingFactor;
 
 		m_modelMat = p_modelMat;
 		m_modelViewProjMatrix = p_modelViewProjMatrix;
-
-		//memcpy(m_materials, p_materials, sizeof(m_materials));
 	}
 
 	glm::mat4	m_modelMat,
@@ -81,10 +78,8 @@ struct UniformObjectData
 
 	float	m_heightScale,
 			m_alphaThreshold,
-			m_emissiveThreshold,
+			m_emissiveIntensity,
 			m_textureTilingFactor;
-
-	//unsigned int m_materials[MaterialType_NumOfTypes];
 };
 
 struct UniformData

+ 193 - 3
Praxis3D/imgui.ini

@@ -4,8 +4,8 @@ Size=400,400
 Collapsed=0
 
 [Window][Dear ImGui Demo]
-Pos=192,219
-Size=396,585
+Pos=102,374
+Size=507,545
 Collapsed=0
 
 [Window][Dear ImGui Stack Tool]
@@ -177,6 +177,36 @@ Pos=479,161
 Size=881,586
 Collapsed=0
 
+[Window][Open a model file##OpenModelFileFileDialog]
+Pos=414,138
+Size=965,668
+Collapsed=0
+
+[Window][Save scene##SaveSceneFileDialog]
+Pos=522,160
+Size=875,613
+Collapsed=0
+
+[Window][The file Already Exist !##Save sceneSaveSceneFileDialogOverWriteDialog]
+Pos=839,440
+Size=240,71
+Collapsed=0
+
+[Window][Open a texture file##OpenTextureFileFileDialog]
+Pos=216,90
+Size=1007,703
+Collapsed=0
+
+[Window][The file Already Exist !##Open a texture fileOpenTextureFileFileDialogOverWriteDialog]
+Pos=599,415
+Size=240,71
+Collapsed=0
+
+[Window][Open scene##OpenSceneFileDialog]
+Pos=599,114
+Size=876,586
+Collapsed=0
+
 [Table][0x9A4BDFDE,4]
 RefScale=13
 Column 0  Sort=0v
@@ -541,8 +571,168 @@ Column 0  Sort=0v
 RefScale=13
 Column 0  Sort=0v
 
+[Table][0x43A5C9E6,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x8AC1E38E,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xACB1D8C2,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x33339EF5,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xBB491CD9,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x05A7E1DA,4]
+RefScale=13
+Column 3  Sort=0^
+
+[Table][0xB9418476,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xACC46DE7,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x12934C07,4]
+RefScale=13
+Column 2  Sort=0^
+
+[Table][0x62AD7CAF,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x8D4D81A0,4]
+RefScale=13
+Column 2  Sort=0^
+
+[Table][0xCD7C3BB5,4]
+RefScale=13
+Column 2  Sort=0^
+
+[Table][0xE2D3918C,4]
+RefScale=13
+Column 3  Sort=0^
+
+[Table][0xF4D8751A,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x295845ED,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xC01D8C5B,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x6FACBB2C,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xBFF4BDBC,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x26CF782C,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x583AB83C,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x54FA0ABF,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xBDBFC309,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x31FE3A81,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x669A699C,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA10B7BE7,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x9E891D9E,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x77CCD428,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xBB0295F3,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x0A1B76A3,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x3720CA94,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x898CEBA0,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x60C92216,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA6234199,4]
+RefScale=13
+Column 3  Sort=0^
+
+[Table][0x946FA1E9,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x7D2A685F,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x001A738B,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xE7D842E3,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0xA07333AE,4]
+RefScale=13
+Column 3  Sort=0^
+
+[Table][0x103CC6F3,4]
+RefScale=13
+Column 0  Sort=0v
+
+[Table][0x58CCE909,4]
+RefScale=13
+Column 0  Sort=0v
+
 [Docking][Data]
-DockSpace         ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,69 Size=1920,1011 Split=X
+DockSpace         ID=0x8B93E3BD Pos=0,69 Size=1920,1011 Split=X
   DockNode        ID=0x00000007 Parent=0x8B93E3BD SizeRef=1456,1011 Split=Y
     DockNode      ID=0x00000005 Parent=0x00000007 SizeRef=1920,725 Split=X
       DockNode    ID=0x00000001 Parent=0x00000005 SizeRef=301,1011 Selected=0xB1B21E90