Implémente un système de culling basé sur la position de la lumière du soleil pour améliorer les performances du rendu des ombres. Crée un thread dédié au culling des objets non visibles par la lumière du soleil. Ajoute une structure de frustum spécifique au culling par la lumière du soleil. Modifie le RenderComponent pour suivre si un objet est visible par la lumière du soleil.
493 lines
19 KiB
C++
493 lines
19 KiB
C++
#pragma once
|
|
#include "../component.h"
|
|
#include "model_class.h"
|
|
#include <memory>
|
|
#include <string>
|
|
#include <map>
|
|
#include <WICTextureLoader.h>
|
|
|
|
// Déclaration externe de la variable globale définie dans application_class.h
|
|
/**
|
|
* Declaration of the global model cache externe variable from application_class.h .
|
|
* This variable is used to cache models loaded from files to avoid reloading them multiple times.
|
|
*/
|
|
extern std::map<std::string, std::shared_ptr<model_class>> g_model_cache;
|
|
|
|
namespace ecs {
|
|
|
|
|
|
class RenderComponent : public Component {
|
|
public:
|
|
/**
|
|
* Builder for the RenderComponent class.
|
|
*/
|
|
RenderComponent() : m_model(nullptr), m_isVisible(true) {}
|
|
~RenderComponent() = default;
|
|
|
|
|
|
/**
|
|
* Initialize the component by setting up the Direct3D device and context from the parent entity.
|
|
* This method is called when the component is added to an entity.
|
|
*/
|
|
void Initialize() override
|
|
{
|
|
if (auto parent = GetParent()) {
|
|
SetDevice(parent->GetDevice());
|
|
SetContext(parent->GetContext());
|
|
}
|
|
|
|
texture_container_buffer = TextureContainer();
|
|
|
|
}
|
|
void Update(float deltaTime) override {}
|
|
|
|
/**
|
|
* Initialize the RenderComponent with a model.
|
|
* This method allows the component to be initialized with an existing model instance.
|
|
* @param model A shared pointer to the model_class instance to use.
|
|
* @return True if initialization was successful, false otherwise.
|
|
*/
|
|
bool InitializeWithModel(std::shared_ptr<model_class> model) {
|
|
if (!model) R_FALSE
|
|
m_model = model;
|
|
R_TRUE
|
|
}
|
|
|
|
/**
|
|
* Initialize the RenderComponent from a model file.
|
|
* This method checks if the model is already cached; if not, it loads the model from the specified file.
|
|
* @param device The Direct3D device used for rendering.
|
|
* @param deviceContext The Direct3D device context used for rendering.
|
|
* @param modelFilename The path to the model file to load.
|
|
* @param textureContainer The container for textures used by the model.
|
|
* @return True if initialization was successful, false otherwise.
|
|
*/
|
|
bool InitializeFromFile(ID3D11Device* device, ID3D11DeviceContext* deviceContext,
|
|
const char* modelFilename, TextureContainer& textureContainer) {
|
|
// Vérifier si le modèle existe déjà dans le cache
|
|
std::string filename(modelFilename);
|
|
auto it = g_model_cache.find(filename);
|
|
if (it != g_model_cache.end()) {
|
|
m_model = it->second;
|
|
} else {
|
|
// Créer un nouveau modèle
|
|
auto new_model = std::make_shared<model_class>();
|
|
if (!new_model->Initialize(device, deviceContext, const_cast<char*>(modelFilename), textureContainer)) {
|
|
R_FALSE
|
|
}
|
|
g_model_cache[filename] = new_model;
|
|
m_model = new_model;
|
|
}
|
|
|
|
m_modelFilePath = modelFilename;
|
|
R_TRUE
|
|
}
|
|
|
|
/**
|
|
* Load textures from a list of file paths into the texture container.
|
|
* This method uses DirectX's WIC texture loader to load textures from the specified paths.
|
|
* @param texturePaths A vector of file paths to the textures to load.
|
|
* @param texturesContainer The container where the loaded textures will be stored.
|
|
* @param device The Direct3D device used for rendering.
|
|
* @param deviceContext The Direct3D device context used for rendering.
|
|
* @return True if all textures were loaded successfully, false otherwise.
|
|
*/
|
|
bool LoadTexturesFromPath(std::vector<std::wstring>& texturePaths, TextureContainer& texturesContainer,
|
|
ID3D11Device* device, ID3D11DeviceContext* deviceContext) {
|
|
HRESULT result;
|
|
|
|
int i = 0;
|
|
for (const auto& texturePath : texturePaths) {
|
|
ID3D11ShaderResourceView* texture = nullptr;
|
|
result = DirectX::CreateWICTextureFromFile(device, deviceContext, texturePath.c_str(), nullptr, &texture);
|
|
if (FAILED(result)) {
|
|
R_FALSE
|
|
}
|
|
texturesContainer.AssignTexture(texturesContainer, texture, texturePath, i);
|
|
i++;
|
|
}
|
|
|
|
R_TRUE
|
|
}
|
|
|
|
/**
|
|
* Get the model associated with this RenderComponent.
|
|
* @return A shared pointer to the model_class instance.
|
|
*/
|
|
std::shared_ptr<model_class> GetModel() const { return m_model; }
|
|
/**
|
|
* Set the model for this RenderComponent.
|
|
* This method allows the component to be set with an existing model instance.
|
|
* @param model A shared pointer to the model_class instance to set.
|
|
*/
|
|
void SetModel(std::shared_ptr<model_class> model) { m_model = model; }
|
|
|
|
/**
|
|
* Get the file path of the model associated with this RenderComponent.
|
|
* @return The file path as a string.
|
|
*/
|
|
const std::string& GetModelFilePath() const { return m_modelFilePath; }
|
|
/**
|
|
* Set the file path of the model for this RenderComponent.
|
|
* This method allows the component to be set with a specific model file path.
|
|
* @param path The file path to set as a string.
|
|
*/
|
|
void SetModelFilePath(const std::string& path) { m_modelFilePath = path; }
|
|
|
|
/**
|
|
* Check if the model is currently visible.
|
|
* @return True if the model is visible, false otherwise.
|
|
*/
|
|
bool IsVisible() const { return m_isVisible; }
|
|
/**
|
|
* Set the visibility of the model.
|
|
* This method allows the component to control whether the model should be rendered or not.
|
|
* @param visible True to make the model visible, false to hide it.
|
|
*/
|
|
void SetVisible(bool visible) { m_isVisible = visible; }
|
|
|
|
/**
|
|
* Get a texture of a specific type by index.
|
|
* This method retrieves the texture from the model based on the specified type and index.
|
|
* @param type The type of texture to retrieve (Diffuse, Normal, Specular, Alpha).
|
|
* @param index The index of the texture to retrieve (default is 0).
|
|
* @return A pointer to the ID3D11ShaderResourceView of the texture, or nullptr if not found.
|
|
*/
|
|
ID3D11ShaderResourceView* GetTexture(TextureType type, int index = 0) {
|
|
if (!m_model) return nullptr;
|
|
|
|
switch (type) {
|
|
case TextureType::Diffuse:
|
|
return m_model->GetTexture(::TextureType::Diffuse, index);
|
|
case TextureType::Normal:
|
|
return m_model->GetTexture(::TextureType::Normal, index);
|
|
case TextureType::Specular:
|
|
return m_model->GetTexture(::TextureType::Specular, index);
|
|
case TextureType::Alpha:
|
|
return m_model->GetTexture(::TextureType::Alpha, index);
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the number of vertices in the model.
|
|
* This method retrieves the vertex count from the model.
|
|
* @return The number of vertices as an integer.
|
|
*/
|
|
int GetIndexCount() const {
|
|
return m_model ? m_model->GetIndexCount() : 0;
|
|
}
|
|
|
|
/**
|
|
* Render the model using the provided device context.
|
|
* This method calls the Render method of the model if it is initialized and visible.
|
|
* @param deviceContext The Direct3D device context used for rendering.
|
|
*/
|
|
void Render(ID3D11DeviceContext* deviceContext) {
|
|
if (m_model && m_isVisible) {
|
|
m_model->Render(deviceContext);
|
|
}
|
|
}
|
|
|
|
void RenderOnlyGeometryFromSun(ID3D11DeviceContext* ctx)
|
|
{
|
|
if (m_model && m_is_in_sun_pov) m_model->Render(ctx);
|
|
|
|
}
|
|
|
|
void set_is_sun_visible(bool v) { m_is_in_sun_pov = v; }
|
|
bool is_in_sun_pov() const { return m_is_in_sun_pov; }
|
|
|
|
/**
|
|
* Serialize the RenderComponent's state to a string.
|
|
* This method is useful for saving the component's state or debugging.
|
|
* @return A string representation of the RenderComponent's state.
|
|
*/
|
|
std::string Serialize() const override {
|
|
if (!m_model) return "RenderComponent:NoModel";
|
|
|
|
TextureContainer texture_container_buffer = m_model->GetTextureContainer();
|
|
|
|
auto serializePaths = [](const std::vector<std::wstring> &paths) -> std::string {
|
|
std::string result;
|
|
for (size_t i = 0; i < paths.size(); ++i) {
|
|
std::string p = std::string(paths[i].begin(), paths[i].end());
|
|
result += p;
|
|
if (i + 1 < paths.size()) {
|
|
result += ","; // virgule entre chemins mais pas après dernier
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
int diffuse_count = (int)texture_container_buffer.diffuse.size();
|
|
int normal_count = (int)texture_container_buffer.normal.size();
|
|
int specular_count = (int)texture_container_buffer.specular.size();
|
|
int alpha_count = (int)texture_container_buffer.alpha.size();
|
|
|
|
std::string diffuse_paths_ = serializePaths(texture_container_buffer.diffusePaths);
|
|
std::string normal_paths_ = serializePaths(texture_container_buffer.normalPaths);
|
|
std::string specular_paths_ = serializePaths(texture_container_buffer.specularPaths);
|
|
std::string alpha_paths_ = serializePaths(texture_container_buffer.alphaPaths);
|
|
|
|
std::stringstream ss;
|
|
ss << "RenderComponent:HasModel:"
|
|
<< is_shadow_caster_ << ":"
|
|
<< diffuse_count << ":" << diffuse_paths_ << ":"
|
|
<< normal_count << ":" << normal_paths_ << ":"
|
|
<< specular_count << ":" << specular_paths_ << ":"
|
|
<< alpha_count << ":" << alpha_paths_;
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
|
|
/**
|
|
* Deserialize the RenderComponent's state from a string.
|
|
* This method parses the string and sets the component's properties accordingly.
|
|
* Note: The model will be loaded separately based on the model file path.
|
|
* @param data The string representation of the RenderComponent's state.
|
|
* @return True if deserialization was successful, otherwise false.
|
|
*/
|
|
bool Deserialize(const std::string& data) override {
|
|
std::stringstream ss(data);
|
|
std::string type;
|
|
|
|
if (!std::getline(ss, type, ':') || type != "RenderComponent")
|
|
R_FALSE
|
|
|
|
std::string token;
|
|
|
|
if (!std::getline(ss, token, ':') || token != "HasModel")
|
|
R_FALSE
|
|
|
|
std::getline(ss,token, ':');
|
|
is_shadow_caster_ = std::stoi(token);
|
|
|
|
int diffuse_count = 0, normal_count = 0, specular_count = 0, alpha_count = 0;
|
|
|
|
std::vector<std::wstring> paths_diffuse, paths_normal, paths_specular, paths_alpha;
|
|
|
|
auto read_count = [&](int& count) -> bool {
|
|
if (!std::getline(ss, token, ':'))
|
|
R_FALSE
|
|
try {
|
|
count = std::stoi(token);
|
|
}
|
|
catch (...) {
|
|
R_FALSE
|
|
}
|
|
R_TRUE
|
|
};
|
|
|
|
auto clean_token = [](std::string& str) {
|
|
// Retirer virgules et espaces
|
|
str.erase(std::remove(str.begin(), str.end(), ','), str.end());
|
|
str.erase(0, str.find_first_not_of(" \t\n\r"));
|
|
str.erase(str.find_last_not_of(" \t\n\r") + 1);
|
|
};
|
|
|
|
auto read_paths = [&](int count, std::vector<std::wstring>& paths) -> bool {
|
|
for (int i = 0; i < count; ++i) {
|
|
if (!std::getline(ss, token, ':'))
|
|
R_FALSE
|
|
|
|
clean_token(token);
|
|
|
|
if (!token.empty()) {
|
|
paths.emplace_back(token.begin(), token.end());
|
|
LOG_INFO("Loaded path: " + std::string(token.begin(), token.end()));
|
|
}
|
|
}
|
|
R_TRUE
|
|
};
|
|
|
|
if (!read_count(diffuse_count)) R_FALSE
|
|
if (!read_paths(diffuse_count, paths_diffuse)) R_FALSE
|
|
|
|
if (!read_count(normal_count)) R_FALSE
|
|
if (!read_paths(normal_count, paths_normal)) R_FALSE
|
|
|
|
if (!read_count(specular_count)) R_FALSE
|
|
if (!read_paths(specular_count, paths_specular)) R_FALSE
|
|
|
|
if (!read_count(alpha_count)) R_FALSE
|
|
if (!read_paths(alpha_count, paths_alpha)) R_FALSE
|
|
|
|
// Libérer textures existantes
|
|
for (auto& tex : texture_container_buffer.diffuse) if (tex) { tex->Release(); tex = nullptr; }
|
|
for (auto& tex : texture_container_buffer.normal) if (tex) { tex->Release(); tex = nullptr; }
|
|
for (auto& tex : texture_container_buffer.specular) if (tex) { tex->Release(); tex = nullptr; }
|
|
for (auto& tex : texture_container_buffer.alpha) if (tex) { tex->Release(); tex = nullptr; }
|
|
|
|
texture_container_buffer.diffuse.clear();
|
|
texture_container_buffer.normal.clear();
|
|
texture_container_buffer.specular.clear();
|
|
texture_container_buffer.alpha.clear();
|
|
|
|
texture_container_buffer.diffusePaths = std::move(paths_diffuse);
|
|
texture_container_buffer.normalPaths = std::move(paths_normal);
|
|
texture_container_buffer.specularPaths = std::move(paths_specular);
|
|
texture_container_buffer.alphaPaths = std::move(paths_alpha);
|
|
|
|
R_TRUE
|
|
}
|
|
|
|
/**
|
|
* Render the ImGui interface for the RenderComponent.
|
|
* This method provides a user interface for inspecting and modifying the component's properties.
|
|
* It includes options to toggle visibility, display model information, and manage textures.
|
|
*/
|
|
void OnImGuiRender() override {
|
|
ImGui::Checkbox("Visible", &m_isVisible);
|
|
C_BOX("Is shadow caster" , &is_shadow_caster_);
|
|
ImGui::Text("Model File Path: %s", m_modelFilePath.c_str());
|
|
if (m_model) {
|
|
ImGui::Text("Index Count: %d", m_model->GetIndexCount());
|
|
} else {
|
|
ImGui::Text("No model loaded.");
|
|
}
|
|
|
|
ImGui::Separator();
|
|
|
|
// Définir les types de textures_
|
|
std::vector<std::string> textureCategories = {
|
|
"Diffuse", "Normal", "Specular", "Alpha"
|
|
};
|
|
|
|
std::vector<TextureType> textureTypes = {
|
|
TextureType::Diffuse, TextureType::Normal,
|
|
TextureType::Specular, TextureType::Alpha
|
|
};
|
|
|
|
// Créer un espace pour afficher les textures_ avec défilement
|
|
ImGui::BeginChild("TextureChild", ImVec2(0, 200), true, ImGuiWindowFlags_HorizontalScrollbar);
|
|
|
|
// Pour chaque type de texture
|
|
for (int typeIndex = 0; typeIndex < textureCategories.size(); typeIndex++)
|
|
{
|
|
TextureType type = textureTypes[typeIndex];
|
|
std::string typeName = textureCategories[typeIndex];
|
|
|
|
// Afficher le titre de la catégorie
|
|
ImGui::Text("%s:", typeName.c_str());
|
|
ImGui::SameLine();
|
|
|
|
// Compter combien de textures_ de ce type existent
|
|
int textureCount = 0;
|
|
while (GetTexture(type, textureCount) != nullptr)
|
|
{
|
|
textureCount++;
|
|
}
|
|
|
|
// Afficher toutes les textures_ existantes
|
|
ImGui::BeginGroup();
|
|
for (int texIndex = 0; texIndex < textureCount; texIndex++)
|
|
{
|
|
ID3D11ShaderResourceView* texture = GetTexture(type, texIndex);
|
|
if (texture)
|
|
{
|
|
// ID unique pour chaque bouton de texture
|
|
std::string buttonId = "tex##" +
|
|
std::to_string(typeIndex) + "_" +
|
|
std::to_string(texIndex);
|
|
|
|
if (ImGui::ImageButton(buttonId.c_str(), (ImTextureID)texture, ImVec2(48, 48)))
|
|
{
|
|
// Ouvrir une boîte de dialogue pour changer la texture
|
|
OPENFILENAME ofn;
|
|
WCHAR szFile[260];
|
|
ZeroMemory(&ofn, sizeof(ofn));
|
|
ofn.lStructSize = sizeof(ofn);
|
|
ofn.hwndOwner = NULL;
|
|
ofn.lpstrFile = szFile;
|
|
szFile[0] = '\0';
|
|
ofn.nMaxFile = sizeof(szFile);
|
|
ofn.lpstrFilter = L"Texture\0*.png;*.jpg;*.dds\0";
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrInitialDir = NULL;
|
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
|
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
// Changer la texture existante
|
|
m_model->ChangeTexture(device, context, ofn.lpstrFile, type, texIndex);
|
|
}
|
|
}
|
|
|
|
// Afficher l'indice de texture et prévisualisation au survol
|
|
if (ImGui::IsItemHovered())
|
|
{
|
|
ImGui::BeginTooltip();
|
|
ImGui::Text("%s %d", typeName.c_str(), texIndex);
|
|
ImGui::Image((ImTextureID)texture, ImVec2(192, 192));
|
|
ImGui::EndTooltip();
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
}
|
|
}
|
|
|
|
// Bouton pour ajouter une nouvelle texture
|
|
std::string addButtonLabel = "+##" + std::to_string(typeIndex);
|
|
if (ImGui::Button(addButtonLabel.c_str(), ImVec2(48, 48)))
|
|
{
|
|
// Ouvrir une boîte de dialogue pour ajouter une texture
|
|
OPENFILENAME ofn;
|
|
WCHAR szFile[260];
|
|
ZeroMemory(&ofn, sizeof(ofn));
|
|
ofn.lStructSize = sizeof(ofn);
|
|
ofn.hwndOwner = NULL;
|
|
ofn.lpstrFile = szFile;
|
|
szFile[0] = '\0';
|
|
ofn.nMaxFile = sizeof(szFile);
|
|
ofn.lpstrFilter = L"Texture\0*.png;*.jpg;*.dds\0";
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrInitialDir = NULL;
|
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
|
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
// Ajouter une nouvelle texture
|
|
m_model->AddTexture(device, context, ofn.lpstrFile, type);
|
|
}
|
|
}
|
|
|
|
ImGui::EndGroup();
|
|
ImGui::Separator();
|
|
}
|
|
|
|
ImGui::EndChild();
|
|
}
|
|
|
|
void SetDevice (ID3D11Device* dev) { device = dev; }
|
|
void SetContext(ID3D11DeviceContext* ctx) { context = ctx; }
|
|
|
|
void SetTextureContainer(const TextureContainer& texContainer) { texture_container_buffer = texContainer; }
|
|
const TextureContainer& GetTextureContainerBuffer() const { return texture_container_buffer; }
|
|
|
|
/**
|
|
* Get whether the model casts shadows.
|
|
* @return True if the model casts shadows, false otherwise.
|
|
*/
|
|
bool IsShadowCaster() const { return is_shadow_caster_; }
|
|
/**
|
|
* Set whether the model casts shadows.
|
|
* @param isCaster True to make the model cast shadows, false otherwise.
|
|
*/
|
|
void SetShadowCaster(bool isCaster) { is_shadow_caster_ = isCaster; }
|
|
|
|
private:
|
|
std::shared_ptr<model_class> m_model;
|
|
std::string m_modelFilePath;
|
|
bool m_isVisible;
|
|
ID3D11Device* device;
|
|
ID3D11DeviceContext* context;
|
|
TextureContainer texture_container_buffer;
|
|
bool is_shadow_caster_ = true;
|
|
bool m_is_in_sun_pov;
|
|
};
|
|
|
|
} // namespace ecs
|