texture import block compression (#685)

This commit is contained in:
Turánszki János
2023-05-27 13:51:40 +02:00
committed by GitHub
parent 1475a34185
commit c037df33a7
34 changed files with 8104 additions and 643 deletions
+102 -64
View File
@@ -1,6 +1,8 @@
#include "stdafx.h"
#include "MaterialWindow.h"
#include <sstream>
using namespace wi::graphics;
using namespace wi::ecs;
using namespace wi::scene;
@@ -130,6 +132,18 @@ void MaterialWindow::Create(EditorComponent* _editor)
});
AddWidget(&outlineCheckBox);
preferUncompressedCheckBox.Create("Prefer Uncompressed Textures: ");
preferUncompressedCheckBox.SetTooltip("For uncompressed textures (jpg, png, etc.) or transcodable textures (KTX2, Basis) here it is possible to enable/disable auto block compression on importing. \nBlock compression can reduce GPU memory usage and improve performance, but it can result in degraded quality.");
preferUncompressedCheckBox.SetPos(XMFLOAT2(x, y += step));
preferUncompressedCheckBox.SetSize(XMFLOAT2(hei, hei));
preferUncompressedCheckBox.OnClick([&](wi::gui::EventArgs args) {
MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity);
if (material != nullptr)
material->SetPreferUncompressedTexturesEnabled(args.bValue);
textureSlotComboBox.SetSelected(textureSlotComboBox.GetSelected());
});
AddWidget(&preferUncompressedCheckBox);
shaderTypeComboBox.Create("Shader: ");
shaderTypeComboBox.SetTooltip("Select a shader for this material. \nCustom shaders (*) will also show up here (see wi::renderer:RegisterCustomShader() for more info.)\nNote that custom shaders (*) can't select between blend modes, as they are created with an explicit blend mode.");
@@ -577,63 +591,88 @@ void MaterialWindow::Create(EditorComponent* _editor)
break;
}
}
textureSlotComboBox.OnSelect([this](wi::gui::EventArgs args)
textureSlotComboBox.OnSelect([this](wi::gui::EventArgs args) {
std::string tooltiptext;
switch (args.iValue)
{
case MaterialComponent::BASECOLORMAP:
tooltiptext = "RGBA: Basecolor";
break;
case MaterialComponent::NORMALMAP:
tooltiptext = "RG: Normal";
break;
case MaterialComponent::SURFACEMAP:
tooltiptext = "Default workflow: R: Occlusion, G: Roughness, B: Metalness, A: Reflectance\nSpecular-glossiness workflow: RGB: Specular color (f0), A: smoothness";
break;
case MaterialComponent::EMISSIVEMAP:
tooltiptext = "RGBA: Emissive";
break;
case MaterialComponent::OCCLUSIONMAP:
tooltiptext = "R: Occlusion";
break;
case MaterialComponent::DISPLACEMENTMAP:
tooltiptext = "R: Displacement heightmap";
break;
case MaterialComponent::TRANSMISSIONMAP:
tooltiptext = "R: Transmission factor";
break;
case MaterialComponent::SHEENCOLORMAP:
tooltiptext = "RGB: Sheen color";
break;
case MaterialComponent::SHEENROUGHNESSMAP:
tooltiptext = "A: Roughness";
break;
case MaterialComponent::CLEARCOATMAP:
tooltiptext = "R: Clearcoat factor";
break;
case MaterialComponent::CLEARCOATROUGHNESSMAP:
tooltiptext = "G: Roughness";
break;
case MaterialComponent::CLEARCOATNORMALMAP:
tooltiptext = "RG: Normal";
break;
case MaterialComponent::SPECULARMAP:
tooltiptext = "RGB: Specular color, A: Specular intensity [non-metal]";
break;
case MaterialComponent::ANISOTROPYMAP:
tooltiptext = "RG: The anisotropy texture. Red and green channels represent the anisotropy direction in [-1, 1] tangent, bitangent space.\nThe vector is rotated by anisotropyRotation, and multiplied by anisotropyStrength, to obtain the final anisotropy direction and strength.";
break;
default:
break;
}
switch (args.iValue)
{
case MaterialComponent::BASECOLORMAP:
textureSlotButton.SetTooltip("RGBA: Basecolor");
break;
case MaterialComponent::NORMALMAP:
textureSlotButton.SetTooltip("RGB: Normal");
break;
case MaterialComponent::SURFACEMAP:
textureSlotButton.SetTooltip("Default workflow: R: Occlusion, G: Roughness, B: Metalness, A: Reflectance\nSpecular-glossiness workflow: RGB: Specular color (f0), A: smoothness");
break;
case MaterialComponent::EMISSIVEMAP:
textureSlotButton.SetTooltip("RGBA: Emissive");
break;
case MaterialComponent::OCCLUSIONMAP:
textureSlotButton.SetTooltip("R: Occlusion");
break;
case MaterialComponent::DISPLACEMENTMAP:
textureSlotButton.SetTooltip("R: Displacement heightmap");
break;
case MaterialComponent::TRANSMISSIONMAP:
textureSlotButton.SetTooltip("R: Transmission factor");
break;
case MaterialComponent::SHEENCOLORMAP:
textureSlotButton.SetTooltip("RGB: Sheen color");
break;
case MaterialComponent::SHEENROUGHNESSMAP:
textureSlotButton.SetTooltip("A: Roughness");
break;
case MaterialComponent::CLEARCOATMAP:
textureSlotButton.SetTooltip("R: Clearcoat factor");
break;
case MaterialComponent::CLEARCOATROUGHNESSMAP:
textureSlotButton.SetTooltip("G: Roughness");
break;
case MaterialComponent::CLEARCOATNORMALMAP:
textureSlotButton.SetTooltip("RGB: Normal");
break;
case MaterialComponent::SPECULARMAP:
textureSlotButton.SetTooltip("RGB: Specular color, A: Specular intensity [non-metal]");
break;
case MaterialComponent::ANISOTROPYMAP:
textureSlotButton.SetTooltip("RG: The anisotropy texture. Red and green channels represent the anisotropy direction in [-1, 1] tangent, bitangent space.\nThe vector is rotated by anisotropyRotation, and multiplied by anisotropyStrength, to obtain the final anisotropy direction and strength.");
break;
default:
break;
}
MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity);
if (material == nullptr)
return;
MaterialComponent* material = editor->GetCurrentScene().materials.GetComponent(entity);
if (material != nullptr)
{
textureSlotButton.SetImage(material->textures[args.iValue].resource);
if (material->textures[args.iValue].resource.IsValid())
{
const Texture& texture = material->textures[args.iValue].resource.GetTexture();
tooltiptext += "\nResolution: " + std::to_string(texture.desc.width) + " * " + std::to_string(texture.desc.height);
tooltiptext += "\nMip levels: " + std::to_string(texture.desc.mip_levels);
tooltiptext += "\nFormat: ";
tooltiptext += GetFormatString(texture.desc.format);
});
std::stringstream ss;
ss << std::fixed << std::setprecision(2);
const size_t texture_size = ComputeTextureMemorySizeInBytes(texture.desc);
if (texture_size >= 1024ull * 1024ull)
{
ss << "\nMemory: " << ComputeTextureMemorySizeInBytes(texture.desc) / 1024.0f / 1024.0f << " MB";
}
else
{
ss << "\nMemory: " << ComputeTextureMemorySizeInBytes(texture.desc) / 1024.0f << " KB";
}
tooltiptext += ss.str();
}
}
textureSlotButton.SetTooltip(tooltiptext);
});
textureSlotComboBox.SetSelected(0);
textureSlotComboBox.SetTooltip("Choose the texture slot to modify.");
AddWidget(&textureSlotComboBox);
@@ -673,22 +712,14 @@ void MaterialWindow::Create(EditorComponent* _editor)
params.extensions = wi::resourcemanager::GetSupportedImageExtensions();
wi::helper::FileDialog(params, [this, material, slot](std::string fileName) {
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
wi::resourcemanager::Flags flags = wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA;
switch (slot)
{
case MaterialComponent::NORMALMAP:
case MaterialComponent::CLEARCOATNORMALMAP:
flags |= wi::resourcemanager::Flags::IMPORT_NORMALMAP;
break;
default:
break;
};
wi::resourcemanager::Flags flags = material->GetTextureSlotResourceFlags(MaterialComponent::TEXTURESLOT(slot));
material->textures[slot].resource = wi::resourcemanager::Load(fileName, flags);
material->textures[slot].name = fileName;
material->SetDirty();
textureSlotLabel.SetText(wi::helper::GetFileNameFromPath(fileName));
});
textureSlotComboBox.SetSelected(slot);
});
});
}
});
AddWidget(&textureSlotButton);
@@ -724,6 +755,7 @@ void MaterialWindow::Create(EditorComponent* _editor)
void MaterialWindow::SetEntity(Entity entity)
{
bool changed = this->entity != entity;
this->entity = entity;
Scene& scene = editor->GetCurrentScene();
@@ -755,6 +787,7 @@ void MaterialWindow::SetEntity(Entity entity)
windCheckBox.SetCheck(material->IsUsingWind());
doubleSidedCheckBox.SetCheck(material->IsDoubleSided());
outlineCheckBox.SetCheck(material->IsOutlineEnabled());
preferUncompressedCheckBox.SetCheck(material->IsPreferUncompressedTexturesEnabled());
normalMapSlider.SetValue(material->normalMapStrength);
roughnessSlider.SetValue(material->roughness);
reflectanceSlider.SetValue(material->reflectance);
@@ -857,6 +890,10 @@ void MaterialWindow::SetEntity(Entity entity)
textureSlotButton.SetImage(material->textures[slot].resource);
textureSlotLabel.SetText(wi::helper::GetFileNameFromPath(material->textures[slot].name));
textureSlotUvsetField.SetText(std::to_string(material->textures[slot].uvset));
if (changed)
{
textureSlotComboBox.SetSelected(slot);
}
}
else
{
@@ -920,6 +957,7 @@ void MaterialWindow::ResizeLayout()
add_right(windCheckBox);
add_right(doubleSidedCheckBox);
add_right(outlineCheckBox);
add_right(preferUncompressedCheckBox);
add(shaderTypeComboBox);
add(blendModeComboBox);
add(shadingRateComboBox);
+1
View File
@@ -20,6 +20,7 @@ public:
wi::gui::CheckBox windCheckBox;
wi::gui::CheckBox doubleSidedCheckBox;
wi::gui::CheckBox outlineCheckBox;
wi::gui::CheckBox preferUncompressedCheckBox;
wi::gui::ComboBox shaderTypeComboBox;
wi::gui::ComboBox blendModeComboBox;
wi::gui::ComboBox shadingRateComboBox;
+2 -23
View File
@@ -104,7 +104,7 @@ namespace tinygltf
auto resource = wi::resourcemanager::Load(
image->uri,
wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA,
wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA | wi::resourcemanager::Flags::IMPORT_DELAY,
(const uint8_t*)bytes,
(size_t)size
);
@@ -114,10 +114,6 @@ namespace tinygltf
return false;
}
image->width = resource.GetTexture().desc.width;
image->height = resource.GetTexture().desc.height;
image->component = 4;
wi::resourcemanager::ResourceSerializer* seri = (wi::resourcemanager::ResourceSerializer*)userdata;
seri->resources.push_back(resource);
@@ -555,7 +551,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::BASECOLORMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::BASECOLORMAP].name = img.uri;
material.textures[MaterialComponent::BASECOLORMAP].uvset = baseColorTexture->second.TextureTexCoord();
}
@@ -568,7 +563,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::NORMALMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::NORMALMAP].name = img.uri;
material.textures[MaterialComponent::NORMALMAP].uvset = normalTexture->second.TextureTexCoord();
}
@@ -581,7 +575,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::SURFACEMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::SURFACEMAP].name = img.uri;
material.textures[MaterialComponent::SURFACEMAP].uvset = metallicRoughnessTexture->second.TextureTexCoord();
}
@@ -594,7 +587,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::EMISSIVEMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::EMISSIVEMAP].name = img.uri;
material.textures[MaterialComponent::EMISSIVEMAP].uvset = emissiveTexture->second.TextureTexCoord();
}
@@ -607,7 +599,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::OCCLUSIONMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::OCCLUSIONMAP].name = img.uri;
material.textures[MaterialComponent::OCCLUSIONMAP].uvset = occlusionTexture->second.TextureTexCoord();
material.SetOcclusionEnabled_Secondary(true);
@@ -679,7 +670,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::TRANSMISSIONMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::TRANSMISSIONMAP].name = img.uri;
material.textures[MaterialComponent::TRANSMISSIONMAP].uvset = (uint32_t)ext_transmission->second.Get("transmissionTexture").Get("texCoord").Get<int>();
}
@@ -703,7 +693,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::BASECOLORMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::BASECOLORMAP].name = img.uri;
material.textures[MaterialComponent::BASECOLORMAP].uvset = (uint32_t)specularGlossinessWorkflow->second.Get("diffuseTexture").Get("texCoord").Get<int>();
}
@@ -717,7 +706,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::SURFACEMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::SURFACEMAP].name = img.uri;
material.textures[MaterialComponent::SURFACEMAP].uvset = (uint32_t)specularGlossinessWorkflow->second.Get("specularGlossinessTexture").Get("texCoord").Get<int>();
}
@@ -771,7 +759,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::SHEENCOLORMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::SHEENCOLORMAP].name = img.uri;
material.textures[MaterialComponent::SHEENCOLORMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -791,7 +778,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::SHEENROUGHNESSMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::SHEENROUGHNESSMAP].name = img.uri;
material.textures[MaterialComponent::SHEENROUGHNESSMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -827,7 +813,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::CLEARCOATMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::CLEARCOATMAP].name = img.uri;
material.textures[MaterialComponent::CLEARCOATMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -847,7 +832,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::CLEARCOATROUGHNESSMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::CLEARCOATROUGHNESSMAP].name = img.uri;
material.textures[MaterialComponent::CLEARCOATROUGHNESSMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -862,7 +846,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::CLEARCOATNORMALMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::CLEARCOATNORMALMAP].name = img.uri;
material.textures[MaterialComponent::CLEARCOATNORMALMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -907,7 +890,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::SURFACEMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::SURFACEMAP].name = img.uri;
material.textures[MaterialComponent::SURFACEMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -922,7 +904,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::SPECULARMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::SPECULARMAP].name = img.uri;
material.textures[MaterialComponent::SPECULARMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -942,7 +923,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::SPECULARMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::SPECULARMAP].name = img.uri;
material.textures[MaterialComponent::SPECULARMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -983,7 +963,6 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::ANISOTROPYMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::ANISOTROPYMAP].name = img.uri;
material.textures[MaterialComponent::ANISOTROPYMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
@@ -1010,12 +989,12 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
img_source = tex.extensions["KHR_texture_basisu"].Get("source").Get<int>();
}
auto& img = state.gltfModel.images[img_source];
material.textures[MaterialComponent::ANISOTROPYMAP].resource = wi::resourcemanager::Load(img.uri);
material.textures[MaterialComponent::ANISOTROPYMAP].name = img.uri;
material.textures[MaterialComponent::ANISOTROPYMAP].uvset = (uint32_t)param.Get("texCoord").Get<int>();
}
}
material.CreateRenderData();
}
// Create meshes:
+1 -1
View File
@@ -1340,7 +1340,7 @@ void PaintToolWindow::RecordHistory(bool start, CommandList cmd)
);
}
assert(cmd.IsValid());
device->CopyResource(&newslot.texture, &editTexture.texture, cmd);
wi::renderer::CopyTexture2D(newslot.texture, 0, 0, 0, editTexture.texture, 0, cmd); // custom copy with format conversion capability!
ReplaceEditTextureSlot(*material, newslot);
}
+1
View File
@@ -1,5 +1,6 @@
This file contains changelog of wi::Archive versions
89: distortion particles must use the normal map slot from now on
88: volumetric clouds second layer
87: DDGI serialization: added grid_extents and smooth_backface
86: serialized volumetric clouds weather map, removed unused values and remapped values from VolumetricCloudParameters
@@ -54,6 +54,18 @@
<None Include="$(MSBuildThisFileDirectory)voxelHF.hlsli" />
</ItemGroup>
<ItemGroup>
<FxCompile Include="$(MSBuildThisFileDirectory)blockcompressCS_BC1.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)blockcompressCS_BC3.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)blockcompressCS_BC5.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)bloomseparateCS.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
@@ -2622,6 +2634,9 @@
</FxCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)compressonator\bcn_common_api.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)compressonator\bcn_common_kernel.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)compressonator\common_def.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr2\ffx_common_types.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr2\ffx_core.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr2\ffx_core_cpu.h" />
@@ -2645,6 +2660,12 @@
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr2\ffx_fsr2_sample.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr2\ffx_fsr2_upsample.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr2\ffx_spd.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr\ffx_a.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr\ffx_fsr1.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-shadows-dnsr\ffx_denoiser_shadows_filter.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-shadows-dnsr\ffx_denoiser_shadows_prepare.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-shadows-dnsr\ffx_denoiser_shadows_tileclassification.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-shadows-dnsr\ffx_denoiser_shadows_util.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_BVH.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_DDGI.h" />
@@ -34,6 +34,15 @@
<Filter Include="ffx-fsr2">
<UniqueIdentifier>{902ab028-5d33-4517-a981-4b5adc0f7031}</UniqueIdentifier>
</Filter>
<Filter Include="compressonator">
<UniqueIdentifier>{913dd8d5-7a4e-4a41-9737-4c690309165e}</UniqueIdentifier>
</Filter>
<Filter Include="ffx-fsr">
<UniqueIdentifier>{a0f04960-eae7-45c2-a6d8-c0c25ec3b333}</UniqueIdentifier>
</Filter>
<Filter Include="ffx-shadows-dnsr">
<UniqueIdentifier>{2bb6f2d6-f3e1-4501-95bc-bd4a0ca64c4b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)globals.hlsli">
@@ -1079,6 +1088,15 @@
<FxCompile Include="$(MSBuildThisFileDirectory)yuv_to_rgbCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)blockcompressCS_BC1.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)blockcompressCS_BC3.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)blockcompressCS_BC5.hlsl">
<Filter>CS</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop.h">
@@ -1201,5 +1219,32 @@
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_VXGI.h">
<Filter>interop</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)compressonator\bcn_common_api.h">
<Filter>compressonator</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)compressonator\bcn_common_kernel.h">
<Filter>compressonator</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)compressonator\common_def.h">
<Filter>compressonator</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr\ffx_a.h">
<Filter>ffx-fsr</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-fsr\ffx_fsr1.h">
<Filter>ffx-fsr</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-shadows-dnsr\ffx_denoiser_shadows_filter.h">
<Filter>ffx-shadows-dnsr</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-shadows-dnsr\ffx_denoiser_shadows_prepare.h">
<Filter>ffx-shadows-dnsr</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-shadows-dnsr\ffx_denoiser_shadows_tileclassification.h">
<Filter>ffx-shadows-dnsr</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)ffx-shadows-dnsr\ffx_denoiser_shadows_util.h">
<Filter>ffx-shadows-dnsr</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -0,0 +1,224 @@
#include "globals.hlsli"
// Compressonator is better quality but slower:
#define USE_COMPRESSONATOR
#ifdef USE_COMPRESSONATOR
#pragma dxc diagnostic push
#pragma dxc diagnostic ignored "-Wambig-lit-shift"
#pragma dxc diagnostic ignored "-Wunused-value"
#define ASPM_HLSL
#include "compressonator/bcn_common_kernel.h"
#pragma dxc diagnostic pop
#else
#include "BlockCompress.hlsli"
#endif // USE_COMPRESSONATOR
#if !defined(BC3) && !defined(BC5)
#define BC1
#endif // !BC3 && !BC5
Texture2D input : register(t0);
#ifdef BC1
RWTexture2D<uint2> output : register(u0);
#endif // BC1
#ifdef BC3
RWTexture2D<uint4> output : register(u0);
#endif // BC3
#ifdef BC5
RWTexture2D<uint4> output : register(u0);
#endif // BC5
#if 0
// Dithering is to fix bad-looking gradients in BC1 and BC3 RGB compression:
#define DITHER(color) (color + (dither((float2)DTid.xy) - 0.5f) / 64.0f)
#else
#define DITHER(color) (color)
#endif
[numthreads(8, 8, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
#ifdef BC1
float3 block[16];
#endif // BC1
#ifdef BC3
float3 block[16];
float block_a[16];
#endif // BC3
#ifdef BC5
float block_u[16];
float block_v[16];
#endif // BC5
uint2 dim;
input.GetDimensions(dim.x, dim.y);
const float2 dim_rcp = rcp(dim);
const float2 uv = float2(DTid.xy * 4 + 1) * dim_rcp;
//SUB-BLOCK///////////////////////////////////////////////////////////////////////
float4 red = input.GatherRed(sampler_linear_clamp, uv, int2(0, 0));
float4 green = input.GatherGreen(sampler_linear_clamp, uv, int2(0, 0));
float4 blue = input.GatherBlue(sampler_linear_clamp, uv, int2(0, 0));
float4 alpha = input.GatherAlpha(sampler_linear_clamp, uv, int2(0, 0));
#if defined(BC1) || defined(BC3)
block[0] = DITHER(float3(red[3], green[3], blue[3]));
block[1] = DITHER(float3(red[2], green[2], blue[2]));
block[4] = DITHER(float3(red[0], green[0], blue[0]));
block[5] = DITHER(float3(red[1], green[1], blue[1]));
#endif // BC1 || BC3
#ifdef BC3
block_a[0] = alpha[3];
block_a[1] = alpha[2];
block_a[4] = alpha[0];
block_a[5] = alpha[1];
#endif // BC3
#ifdef BC5
block_u[0] = red[3];
block_u[1] = red[2];
block_u[4] = red[0];
block_u[5] = red[1];
block_v[0] = green[3];
block_v[1] = green[2];
block_v[4] = green[0];
block_v[5] = green[1];
#endif // BC5
//SUB-BLOCK///////////////////////////////////////////////////////////////////////
red = input.GatherRed(sampler_linear_clamp, uv, int2(2, 0));
green = input.GatherGreen(sampler_linear_clamp, uv, int2(2, 0));
blue = input.GatherBlue(sampler_linear_clamp, uv, int2(2, 0));
alpha = input.GatherAlpha(sampler_linear_clamp, uv, int2(2, 0));
#if defined(BC1) || defined(BC3)
block[2] = DITHER(float3(red[3], green[3], blue[3]));
block[3] = DITHER(float3(red[2], green[2], blue[2]));
block[6] = DITHER(float3(red[0], green[0], blue[0]));
block[7] = DITHER(float3(red[1], green[1], blue[1]));
#endif // BC1 || BC3
#ifdef BC3
block_a[2] = alpha[3];
block_a[3] = alpha[2];
block_a[6] = alpha[0];
block_a[7] = alpha[1];
#endif // BC3
#ifdef BC5
block_u[2] = red[3];
block_u[3] = red[2];
block_u[6] = red[0];
block_u[7] = red[1];
block_v[2] = green[3];
block_v[3] = green[2];
block_v[6] = green[0];
block_v[7] = green[1];
#endif // BC5
//SUB-BLOCK///////////////////////////////////////////////////////////////////////
red = input.GatherRed(sampler_linear_clamp, uv, int2(0, 2));
green = input.GatherGreen(sampler_linear_clamp, uv, int2(0, 2));
blue = input.GatherBlue(sampler_linear_clamp, uv, int2(0, 2));
alpha = input.GatherAlpha(sampler_linear_clamp, uv, int2(0, 2));
#if defined(BC1) || defined(BC3)
block[8] = DITHER(float3(red[3], green[3], blue[3]));
block[9] = DITHER(float3(red[2], green[2], blue[2]));
block[12] = DITHER(float3(red[0], green[0], blue[0]));
block[13] = DITHER(float3(red[1], green[1], blue[1]));
#endif // BC1 || BC3
#ifdef BC3
block_a[8] = alpha[3];
block_a[9] = alpha[2];
block_a[12] = alpha[0];
block_a[13] = alpha[1];
#endif // BC3
#ifdef BC5
block_u[8] = red[3];
block_u[9] = red[2];
block_u[12] = red[0];
block_u[13] = red[1];
block_v[8] = green[3];
block_v[9] = green[2];
block_v[12] = green[0];
block_v[13] = green[1];
#endif // BC5
//SUB-BLOCK///////////////////////////////////////////////////////////////////////
red = input.GatherRed(sampler_linear_clamp, uv, int2(2, 2));
green = input.GatherGreen(sampler_linear_clamp, uv, int2(2, 2));
blue = input.GatherBlue(sampler_linear_clamp, uv, int2(2, 2));
alpha = input.GatherAlpha(sampler_linear_clamp, uv, int2(2, 2));
#if defined(BC1) || defined(BC3)
block[10] = DITHER(float3(red[3], green[3], blue[3]));
block[11] = DITHER(float3(red[2], green[2], blue[2]));
block[14] = DITHER(float3(red[0], green[0], blue[0]));
block[15] = DITHER(float3(red[1], green[1], blue[1]));
#endif // BC1 || BC3
#ifdef BC3
block_a[10] = alpha[3];
block_a[11] = alpha[2];
block_a[14] = alpha[0];
block_a[15] = alpha[1];
#endif // BC3
#ifdef BC5
block_u[10] = red[3];
block_u[11] = red[2];
block_u[14] = red[0];
block_u[15] = red[1];
block_v[10] = green[3];
block_v[11] = green[2];
block_v[14] = green[0];
block_v[15] = green[1];
#endif // BC5
//COMPRESS-WRITE///////////////////////////////////////////////////////////////////
#ifdef USE_COMPRESSONATOR
#ifdef BC1
output[DTid.xy] = CompressBlockBC1_UNORM(block, CMP_QUALITY2, /*isSRGB =*/ false);
#endif // BC1
#ifdef BC3
output[DTid.xy] = CompressBlockBC3_UNORM(block, block_a, CMP_QUALITY2, /*isSRGB =*/ false);
#endif // BC3
#ifdef BC5
output[DTid.xy] = CompressBlockBC5_UNORM(block_u, block_v, CMP_QUALITY2);
#endif // BC5
#else
#ifdef BC1
output[DTid.xy] = CompressBC1Block(block);
#endif // BC1
#ifdef BC3
output[DTid.xy] = CompressBC3Block(block, block_a);
#endif // BC3
#ifdef BC5
output[DTid.xy] = CompressBC5Block(block_u, block_v);
#endif // BC5
#endif // USE_COMPRESSONATOR
}
@@ -0,0 +1,2 @@
#define BC3
#include "blockcompressCS_BC1.hlsl"
@@ -0,0 +1,2 @@
#define BC5
#include "blockcompressCS_BC1.hlsl"
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,12 @@
#include "ShaderInterop_EmittedParticle.h"
#include "objectHF.hlsli"
#ifdef EMITTEDPARTICLE_DISTORTION
static const uint SLOT = NORMALMAP;
#else
static const uint SLOT = BASECOLORMAP;
#endif // EMITTEDPARTICLE_DISTORTION
[earlydepthstencil]
float4 main(VertextoPixel input) : SV_TARGET
{
@@ -12,14 +18,14 @@ float4 main(VertextoPixel input) : SV_TARGET
float4 color = 1;
[branch]
if (material.textures[BASECOLORMAP].IsValid())
if (material.textures[SLOT].IsValid())
{
color = material.textures[BASECOLORMAP].Sample(sampler_linear_clamp, input.tex.xyxy);
color = material.textures[SLOT].Sample(sampler_linear_clamp, input.tex.xyxy);
[branch]
if (xEmitterOptions & EMITTER_OPTION_BIT_FRAME_BLENDING_ENABLED)
{
float4 color2 = material.textures[BASECOLORMAP].Sample(sampler_linear_clamp, input.tex.zwzw);
float4 color2 = material.textures[SLOT].Sample(sampler_linear_clamp, input.tex.zwzw);
color = lerp(color, color2, input.frameBlend);
}
}
@@ -43,7 +49,6 @@ float4 main(VertextoPixel input) : SV_TARGET
#ifdef EMITTEDPARTICLE_DISTORTION
// just make normal maps blendable:
color.rgb = ApplySRGBCurve_Fast(color.rgb); // note: This texture uses basecolormap slot, and this slot is using SRGB descriptor, so we correct it here for normal map
color.rgb = color.rgb - 0.5f;
#endif // EMITTEDPARTICLE_DISTORTION
+6
View File
@@ -236,6 +236,8 @@ void main(uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid :
{
if (entity.GetFlags() & ENTITY_FLAG_LIGHT_STATIC)
break; // static lights will be skipped here (they are used at lightmap baking)
if (!any(entity.GetColor().rgb))
break;
float3 positionVS = mul(GetCamera().view, float4(entity.position, 1)).xyz;
Sphere sphere = { positionVS.xyz, entity.GetRange() + entity.GetLength() };
if (SphereInsideFrustum(sphere, GroupFrustum, nearClipVS, maxDepthVS))
@@ -258,6 +260,8 @@ void main(uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid :
{
if (entity.GetFlags() & ENTITY_FLAG_LIGHT_STATIC)
break; // static lights will be skipped here (they are used at lightmap baking)
if (!any(entity.GetColor().rgb))
break;
float3 positionVS = mul(GetCamera().view, float4(entity.position, 1)).xyz;
float3 directionVS = mul((float3x3)GetCamera().view, entity.GetDirection());
// Construct a tight fitting sphere around the spotlight cone:
@@ -284,6 +288,8 @@ void main(uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid :
{
if (entity.GetFlags() & ENTITY_FLAG_LIGHT_STATIC)
break; // static lights will be skipped here (they are used at lightmap baking)
if (!any(entity.GetColor().rgb))
break;
AppendEntity_Transparent(i);
AppendEntity_Opaque(i);
}
+1
View File
@@ -17,6 +17,7 @@
#endif
#ifdef WATER
#define DISABLE_ENVMAPS
#define DISABLE_VOXELGI
#endif
+1 -1
View File
@@ -5,7 +5,7 @@ namespace wi
{
// this should always be only INCREMENTED and only if a new serialization is implemeted somewhere!
static constexpr uint64_t __archiveVersion = 88;
static constexpr uint64_t __archiveVersion = 89;
// this is the version number of which below the archive is not compatible with the current version
static constexpr uint64_t __archiveVersionBarrier = 22;
+3
View File
@@ -246,6 +246,9 @@ namespace wi::enums
CSTYPE_GENERATEMIPCHAINCUBE_FLOAT4,
CSTYPE_GENERATEMIPCHAINCUBEARRAY_UNORM4,
CSTYPE_GENERATEMIPCHAINCUBEARRAY_FLOAT4,
CSTYPE_BLOCKCOMPRESS_BC1,
CSTYPE_BLOCKCOMPRESS_BC3,
CSTYPE_BLOCKCOMPRESS_BC5,
CSTYPE_FILTERENVMAP,
CSTYPE_COPYTEXTURE2D_UNORM4,
CSTYPE_COPYTEXTURE2D_FLOAT4,
+4
View File
@@ -428,6 +428,10 @@ namespace wi::gui
{
return font.GetTextA();
}
std::string Widget::GetTooltip() const
{
return tooltipFont.GetTextA();
}
void Widget::SetText(const char* value)
{
font.SetText(value);
+1
View File
@@ -272,6 +272,7 @@ namespace wi::gui
const std::string& GetName() const;
void SetName(const std::string& value);
std::string GetText() const;
std::string GetTooltip() const;
void SetText(const char* value);
void SetText(const std::string& value);
void SetText(std::string&& value);
+172
View File
@@ -1494,6 +1494,146 @@ namespace wi::graphics
return Format::UNKNOWN;
}
}
constexpr const char* GetFormatString(Format format)
{
switch (format)
{
case wi::graphics::Format::UNKNOWN:
return "UNKNOWN";
case wi::graphics::Format::R32G32B32A32_FLOAT:
return "R32G32B32A32_FLOAT";
case wi::graphics::Format::R32G32B32A32_UINT:
return "R32G32B32A32_UINT";
case wi::graphics::Format::R32G32B32A32_SINT:
return "R32G32B32A32_SINT";
case wi::graphics::Format::R32G32B32_FLOAT:
return "R32G32B32_FLOAT";
case wi::graphics::Format::R32G32B32_UINT:
return "R32G32B32_UINT";
case wi::graphics::Format::R32G32B32_SINT:
return "R32G32B32_SINT";
case wi::graphics::Format::R16G16B16A16_FLOAT:
return "R16G16B16A16_FLOAT";
case wi::graphics::Format::R16G16B16A16_UNORM:
return "R16G16B16A16_UNORM";
case wi::graphics::Format::R16G16B16A16_UINT:
return "R16G16B16A16_UINT";
case wi::graphics::Format::R16G16B16A16_SNORM:
return "R16G16B16A16_SNORM";
case wi::graphics::Format::R16G16B16A16_SINT:
return "R16G16B16A16_SINT";
case wi::graphics::Format::R32G32_FLOAT:
return "R32G32_FLOAT";
case wi::graphics::Format::R32G32_UINT:
return "R32G32_UINT";
case wi::graphics::Format::R32G32_SINT:
return "R32G32_SINT";
case wi::graphics::Format::D32_FLOAT_S8X24_UINT:
return "D32_FLOAT_S8X24_UINT";
case wi::graphics::Format::R10G10B10A2_UNORM:
return "R10G10B10A2_UNORM";
case wi::graphics::Format::R10G10B10A2_UINT:
return "R10G10B10A2_UINT";
case wi::graphics::Format::R11G11B10_FLOAT:
return "R11G11B10_FLOAT";
case wi::graphics::Format::R8G8B8A8_UNORM:
return "R8G8B8A8_UNORM";
case wi::graphics::Format::R8G8B8A8_UNORM_SRGB:
return "R8G8B8A8_UNORM_SRGB";
case wi::graphics::Format::R8G8B8A8_UINT:
return "R8G8B8A8_UINT";
case wi::graphics::Format::R8G8B8A8_SNORM:
return "R8G8B8A8_SNORM";
case wi::graphics::Format::R8G8B8A8_SINT:
return "R8G8B8A8_SINT";
case wi::graphics::Format::B8G8R8A8_UNORM:
return "B8G8R8A8_UNORM";
case wi::graphics::Format::B8G8R8A8_UNORM_SRGB:
return "B8G8R8A8_UNORM_SRGB";
case wi::graphics::Format::R16G16_FLOAT:
return "R16G16_FLOAT";
case wi::graphics::Format::R16G16_UNORM:
return "R16G16_UNORM";
case wi::graphics::Format::R16G16_UINT:
return "R16G16_UINT";
case wi::graphics::Format::R16G16_SNORM:
return "R16G16_SNORM";
case wi::graphics::Format::R16G16_SINT:
return "R16G16_SINT";
case wi::graphics::Format::D32_FLOAT:
return "D32_FLOAT";
case wi::graphics::Format::R32_FLOAT:
return "R32_FLOAT";
case wi::graphics::Format::R32_UINT:
return "R32_UINT";
case wi::graphics::Format::R32_SINT:
return "R32_SINT";
case wi::graphics::Format::D24_UNORM_S8_UINT:
return "D24_UNORM_S8_UINT";
case wi::graphics::Format::R9G9B9E5_SHAREDEXP:
return "R9G9B9E5_SHAREDEXP";
case wi::graphics::Format::R8G8_UNORM:
return "R8G8_UNORM";
case wi::graphics::Format::R8G8_UINT:
return "R8G8_UINT";
case wi::graphics::Format::R8G8_SNORM:
return "R8G8_SNORM";
case wi::graphics::Format::R8G8_SINT:
return "R8G8_SINT";
case wi::graphics::Format::R16_FLOAT:
return "R16_FLOAT";
case wi::graphics::Format::D16_UNORM:
return "D16_UNORM";
case wi::graphics::Format::R16_UNORM:
return "R16_UNORM";
case wi::graphics::Format::R16_UINT:
return "R16_UINT";
case wi::graphics::Format::R16_SNORM:
return "R16_SNORM";
case wi::graphics::Format::R16_SINT:
return "R16_SINT";
case wi::graphics::Format::R8_UNORM:
return "R8_UNORM";
case wi::graphics::Format::R8_UINT:
return "R8_UINT";
case wi::graphics::Format::R8_SNORM:
return "R8_SNORM";
case wi::graphics::Format::R8_SINT:
return "R8_SINT";
case wi::graphics::Format::BC1_UNORM:
return "BC1_UNORM";
case wi::graphics::Format::BC1_UNORM_SRGB:
return "BC1_UNORM_SRGB";
case wi::graphics::Format::BC2_UNORM:
return "BC2_UNORM";
case wi::graphics::Format::BC2_UNORM_SRGB:
return "BC2_UNORM_SRGB";
case wi::graphics::Format::BC3_UNORM:
return "BC3_UNORM";
case wi::graphics::Format::BC3_UNORM_SRGB:
return "BC3_UNORM_SRGB";
case wi::graphics::Format::BC4_UNORM:
return "BC4_UNORM";
case wi::graphics::Format::BC4_SNORM:
return "BC4_SNORM";
case wi::graphics::Format::BC5_UNORM:
return "BC5_UNORM";
case wi::graphics::Format::BC5_SNORM:
return "BC5_SNORM";
case wi::graphics::Format::BC6H_UF16:
return "BC6H_UF16";
case wi::graphics::Format::BC6H_SF16:
return "BC6H_SF16";
case wi::graphics::Format::BC7_UNORM:
return "BC7_UNORM";
case wi::graphics::Format::BC7_UNORM_SRGB:
return "BC7_UNORM_SRGB";
case wi::graphics::Format::NV12:
return "NV12";
default:
return "";
}
}
constexpr IndexBufferFormat GetIndexBufferFormat(Format format)
{
switch (format)
@@ -1514,6 +1654,38 @@ namespace wi::graphics
{
return ((value + alignment - 1) / alignment) * alignment;
}
constexpr uint32_t GetMipCount(uint32_t width, uint32_t height, uint32_t depth = 1u)
{
uint32_t mips = 1;
while (width > 1u || height > 1u || depth > 1u)
{
width = std::max(1u, width >> 1u);
height = std::max(1u, height >> 1u);
depth = std::max(1u, depth >> 1u);
mips++;
}
return mips;
}
constexpr size_t ComputeTextureMemorySizeInBytes(const TextureDesc& desc)
{
size_t size = 0;
const uint32_t bytes_per_block = GetFormatStride(desc.format);
const uint32_t pixels_per_block = GetFormatBlockSize(desc.format);
const uint32_t num_blocks_x = desc.width / pixels_per_block;
const uint32_t num_blocks_y = desc.height / pixels_per_block;
const uint32_t mips = desc.mip_levels == 0 ? GetMipCount(desc.width, desc.height, desc.depth) : desc.mip_levels;
for (uint32_t layer = 0; layer < desc.array_size; ++layer)
{
for (uint32_t mip = 0; mip < mips; ++mip)
{
const uint32_t width = std::max(1u, num_blocks_x >> mip);
const uint32_t height = std::max(1u, num_blocks_y >> mip);
const uint32_t depth = std::max(1u, desc.depth >> mip);
size += width * height * depth * bytes_per_block;
}
}
return size;
}
// Deprecated, kept for back-compat:
+1 -1
View File
@@ -3464,7 +3464,7 @@ using namespace dx12_internal;
if (texture->desc.mip_levels == 0)
{
texture->desc.mip_levels = (uint32_t)log2(std::max(texture->desc.width, texture->desc.height)) + 1;
texture->desc.mip_levels = GetMipCount(texture->desc.width, texture->desc.height, texture->desc.depth);
}
internal_state->total_size = 0;
+1 -1
View File
@@ -3946,7 +3946,7 @@ using namespace vulkan_internal;
if (texture->desc.mip_levels == 0)
{
texture->desc.mip_levels = (uint32_t)log2(std::max(texture->desc.width, texture->desc.height)) + 1;
texture->desc.mip_levels = GetMipCount(texture->desc.width, texture->desc.height, texture->desc.depth);
}
VkImageCreateInfo imageInfo = {};
+1 -1
View File
@@ -127,7 +127,7 @@ namespace wi
wi::image::SetCanvas(*this);
wi::font::SetCanvas(*this);
wi::renderer::ProcessDeferredMipGenRequests(cmd);
wi::renderer::ProcessDeferredTextureRequests(cmd);
if (GetGUIBlurredBackground() != nullptr)
{
+1 -1
View File
@@ -708,7 +708,7 @@ namespace wi
// Preparing the frame:
CommandList cmd = device->BeginCommandList();
CommandList cmd_prepareframe = cmd;
wi::renderer::ProcessDeferredMipGenRequests(cmd); // Execute it first thing in the frame here, on main thread, to not allow other thread steal it and execute on different command list!
wi::renderer::ProcessDeferredTextureRequests(cmd); // Execute it first thing in the frame here, on main thread, to not allow other thread steal it and execute on different command list!
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
GraphicsDevice* device = wi::graphics::GetDevice();
wi::renderer::BindCameraCB(
+135 -10
View File
@@ -130,6 +130,7 @@ wi::vector<PaintRadius> paintrads;
wi::SpinLock deferredMIPGenLock;
wi::vector<std::pair<Texture, bool>> deferredMIPGens;
wi::vector<std::pair<Texture, Texture>> deferredBCQueue;
static const uint32_t vertexCount_uvsphere = arraysize(UVSPHERE);
static const uint32_t vertexCount_cone = arraysize(CONE);
@@ -891,6 +892,9 @@ void LoadShaders()
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_GENERATEMIPCHAINCUBE_FLOAT4], "generateMIPChainCubeCS_float4.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_GENERATEMIPCHAINCUBEARRAY_UNORM4], "generateMIPChainCubeArrayCS_unorm4.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_GENERATEMIPCHAINCUBEARRAY_FLOAT4], "generateMIPChainCubeArrayCS_float4.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_BLOCKCOMPRESS_BC1], "blockcompressCS_BC1.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_BLOCKCOMPRESS_BC3], "blockcompressCS_BC3.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_BLOCKCOMPRESS_BC5], "blockcompressCS_BC5.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_FILTERENVMAP], "filterEnvMapCS.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_COPYTEXTURE2D_UNORM4], "copytexture2D_unorm4CS.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_COPYTEXTURE2D_FLOAT4], "copytexture2D_float4CS.cso"); });
@@ -2865,7 +2869,7 @@ void RenderImpostors(
}
}
void ProcessDeferredMipGenRequests(CommandList cmd)
void ProcessDeferredTextureRequests(CommandList cmd)
{
deferredMIPGenLock.lock();
for (auto& it : deferredMIPGens)
@@ -2875,6 +2879,11 @@ void ProcessDeferredMipGenRequests(CommandList cmd)
GenerateMipChain(it.first, MIPGENFILTER_LINEAR, cmd, mipopt);
}
deferredMIPGens.clear();
for (auto& it : deferredBCQueue)
{
BlockCompress(it.first, it.second, cmd);
}
deferredBCQueue.clear();
deferredMIPGenLock.unlock();
}
@@ -8367,7 +8376,6 @@ void GenerateMipChain(const Texture& texture, MIPGENFILTER filter, CommandList c
{
GPUBarrier barriers[] = {
GPUBarrier::Memory(),
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, options.arrayIndex * 6 + 0),
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, options.arrayIndex * 6 + 1),
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, options.arrayIndex * 6 + 2),
@@ -8401,6 +8409,18 @@ void GenerateMipChain(const Texture& texture, MIPGENFILTER filter, CommandList c
for (uint32_t i = 0; i < desc.mip_levels - 1; ++i)
{
{
GPUBarrier barriers[] = {
GPUBarrier::Image(&texture, texture.desc.layout, ResourceState::UNORDERED_ACCESS, i + 1, 0),
GPUBarrier::Image(&texture, texture.desc.layout, ResourceState::UNORDERED_ACCESS, i + 1, 1),
GPUBarrier::Image(&texture, texture.desc.layout, ResourceState::UNORDERED_ACCESS, i + 1, 2),
GPUBarrier::Image(&texture, texture.desc.layout, ResourceState::UNORDERED_ACCESS, i + 1, 3),
GPUBarrier::Image(&texture, texture.desc.layout, ResourceState::UNORDERED_ACCESS, i + 1, 4),
GPUBarrier::Image(&texture, texture.desc.layout, ResourceState::UNORDERED_ACCESS, i + 1, 5),
};
device->Barrier(barriers, arraysize(barriers), cmd);
}
mipgen.texture_output = device->GetDescriptorIndex(&texture, SubresourceType::UAV, i + 1);
mipgen.texture_input = device->GetDescriptorIndex(&texture, SubresourceType::SRV, i);
desc.width = std::max(1u, desc.width / 2);
@@ -8419,10 +8439,17 @@ void GenerateMipChain(const Texture& texture, MIPGENFILTER filter, CommandList c
6,
cmd);
GPUBarrier barriers[] = {
GPUBarrier::Memory(),
};
device->Barrier(barriers, arraysize(barriers), cmd);
{
GPUBarrier barriers[] = {
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, 0),
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, 1),
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, 2),
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, 3),
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, 4),
GPUBarrier::Image(&texture, ResourceState::UNORDERED_ACCESS, texture.desc.layout, i + 1, 5),
};
device->Barrier(barriers, arraysize(barriers), cmd);
}
}
}
@@ -8489,7 +8516,6 @@ void GenerateMipChain(const Texture& texture, MIPGENFILTER filter, CommandList c
{
GPUBarrier barriers[] = {
GPUBarrier::Memory(),
GPUBarrier::Image(&texture,ResourceState::UNORDERED_ACCESS,texture.desc.layout,i + 1),
};
device->Barrier(barriers, arraysize(barriers), cmd);
@@ -8552,7 +8578,6 @@ void GenerateMipChain(const Texture& texture, MIPGENFILTER filter, CommandList c
{
GPUBarrier barriers[] = {
GPUBarrier::Memory(),
GPUBarrier::Image(&texture,ResourceState::UNORDERED_ACCESS,texture.desc.layout,i + 1),
};
device->Barrier(barriers, arraysize(barriers), cmd);
@@ -8568,6 +8593,102 @@ void GenerateMipChain(const Texture& texture, MIPGENFILTER filter, CommandList c
}
}
void BlockCompress(const wi::graphics::Texture& texture_src, const wi::graphics::Texture& texture_bc, wi::graphics::CommandList cmd)
{
const uint32_t block_size = GetFormatBlockSize(texture_bc.desc.format);
TextureDesc desc;
desc.width = std::max(1u, texture_bc.desc.width / block_size);
desc.height = std::max(1u, texture_bc.desc.height / block_size);
desc.bind_flags = BindFlag::UNORDERED_ACCESS;
desc.layout = ResourceState::UNORDERED_ACCESS;
desc.mip_levels = GetMipCount(desc.width, desc.height); // full mipchain
static Texture bc_raw_uint2;
static Texture bc_raw_uint4;
Texture* bc_raw = nullptr;
switch (texture_bc.desc.format)
{
case Format::BC1_UNORM:
case Format::BC1_UNORM_SRGB:
bc_raw = &bc_raw_uint2;
desc.format = Format::R32G32_UINT;
device->BindComputeShader(&shaders[CSTYPE_BLOCKCOMPRESS_BC1], cmd);
break;
case Format::BC3_UNORM:
case Format::BC3_UNORM_SRGB:
bc_raw = &bc_raw_uint4;
desc.format = Format::R32G32B32A32_UINT;
device->BindComputeShader(&shaders[CSTYPE_BLOCKCOMPRESS_BC3], cmd);
break;
case Format::BC5_UNORM:
bc_raw = &bc_raw_uint4;
desc.format = Format::R32G32B32A32_UINT;
device->BindComputeShader(&shaders[CSTYPE_BLOCKCOMPRESS_BC5], cmd);
break;
default:
assert(0); // not supported
return;
}
if (!bc_raw->IsValid() || bc_raw->desc.width < desc.width || bc_raw->desc.height < desc.height)
{
device->CreateTexture(&desc, nullptr, bc_raw);
device->SetName(bc_raw, "bc_raw");
for (uint32_t i = 0; i < bc_raw->desc.mip_levels; ++i)
{
int subresource_index = device->CreateSubresource(bc_raw, SubresourceType::UAV, 0, 1, i, 1);
assert(subresource_index == i);
}
}
device->EventBegin("BlockCompress", cmd);
for (uint32_t mip = 0; mip < desc.mip_levels; ++mip)
{
const uint32_t width = std::max(1u, desc.width >> mip);
const uint32_t height = std::max(1u, desc.height >> mip);
device->BindResource(&texture_src, 0, cmd, mip);
device->BindUAV(bc_raw, 0, cmd, mip);
device->Dispatch((width + 7u) / 8u, (height + 7u) / 8u, 1, cmd);
}
GPUBarrier barriers[] = {
GPUBarrier::Image(bc_raw, ResourceState::UNORDERED_ACCESS, ResourceState::COPY_SRC),
GPUBarrier::Image(&texture_bc, texture_bc.desc.layout, ResourceState::COPY_DST),
};
device->Barrier(barriers, arraysize(barriers), cmd);
for (uint32_t mip = 0; mip < texture_bc.desc.mip_levels; ++mip)
{
const uint32_t width = std::max(1u, desc.width >> mip);
const uint32_t height = std::max(1u, desc.height >> mip);
Box box;
box.left = 0;
box.right = width;
box.top = 0;
box.bottom = height;
box.front = 0;
box.back = 1;
device->CopyTexture(
&texture_bc, 0, 0, 0, mip, 0,
bc_raw, std::min(mip, bc_raw->desc.mip_levels - 1), 0,
cmd,
&box
);
}
for (int i = 0; i < arraysize(barriers); ++i)
{
std::swap(barriers[i].image.layout_before, barriers[i].image.layout_after);
}
device->Barrier(barriers, arraysize(barriers), cmd);
device->EventEnd(cmd);
}
void CopyTexture2D(const Texture& dst, int DstMIP, int DstX, int DstY, const Texture& src, int SrcMIP, CommandList cmd, BORDEREXPANDSTYLE borderExpand)
{
const TextureDesc& desc_dst = dst.GetDesc();
@@ -8627,10 +8748,8 @@ void CopyTexture2D(const Texture& dst, int DstMIP, int DstX, int DstY, const Tex
device->Dispatch((cb.xCopySrcSize.x + 7) / 8, (cb.xCopySrcSize.y + 7) / 8, 1, cmd);
{
GPUBarrier barriers[] = {
GPUBarrier::Memory(),
GPUBarrier::Image(&dst,ResourceState::UNORDERED_ACCESS,dst.desc.layout, DstMIP),
};
device->Barrier(barriers, arraysize(barriers), cmd);
@@ -15440,6 +15559,12 @@ void AddDeferredMIPGen(const Texture& texture, bool preserve_coverage)
deferredMIPGens.push_back(std::make_pair(texture, preserve_coverage));
deferredMIPGenLock.unlock();
}
void AddDeferredBlockCompression(const wi::graphics::Texture& texture_src, const wi::graphics::Texture& texture_bc)
{
deferredMIPGenLock.lock();
deferredBCQueue.push_back(std::make_pair(texture_src, texture_bc));
deferredMIPGenLock.unlock();
}
+8 -2
View File
@@ -217,8 +217,8 @@ namespace wi::renderer
uint32_t flags = DRAWSCENE_OPAQUE
);
// Render mip levels for textures that reqested it:
void ProcessDeferredMipGenRequests(wi::graphics::CommandList cmd);
// Process deferred requests such as AddDeferredMIPGen and AddDeferredBlockCompression:
void ProcessDeferredTextureRequests(wi::graphics::CommandList cmd);
// Compute volumetric cloud shadow data
void ComputeVolumetricCloudShadows(
@@ -908,6 +908,11 @@ namespace wi::renderer
};
void GenerateMipChain(const wi::graphics::Texture& texture, MIPGENFILTER filter, wi::graphics::CommandList cmd, const MIPGEN_OPTIONS& options = {});
// Compress a texture into Block Compressed format
// texture_src : source uncompressed texture
// texture_bc : edstination comporessed texture, must be a supported BC format (BC1/BC3/BC5)
void BlockCompress(const wi::graphics::Texture& texture_src, const wi::graphics::Texture& texture_bc, wi::graphics::CommandList cmd);
enum BORDEREXPANDSTYLE
{
BORDEREXPAND_DISABLE,
@@ -1093,6 +1098,7 @@ namespace wi::renderer
// Add a texture that should be mipmapped whenever it is feasible to do so
void AddDeferredMIPGen(const wi::graphics::Texture& texture, bool preserve_coverage = false);
void AddDeferredBlockCompression(const wi::graphics::Texture& texture_src, const wi::graphics::Texture& texture_bc);
struct CustomShader
{
File diff suppressed because it is too large Load Diff
+6
View File
@@ -33,6 +33,10 @@ namespace wi
void SetSound(const wi::audio::Sound& sound);
void SetScript(const std::string& script);
void SetVideo(const wi::video::Video& script);
// Resource marked for recreate on resourcemanager::Load()
// It keeps embedded file data if exists
void SetOutdated();
};
namespace resourcemanager
@@ -57,6 +61,8 @@ namespace wi
IMPORT_COLORGRADINGLUT = 1 << 0, // image import will convert resource to 3D color grading LUT
IMPORT_RETAIN_FILEDATA = 1 << 1, // file data will be kept for later reuse. This is necessary for keeping the resource serializable
IMPORT_NORMALMAP = 1 << 2, // image import will try to use optimal normal map encoding
IMPORT_BLOCK_COMPRESSED = 1 << 3, // image import will request block compression for uncompressed or transcodable formats
IMPORT_DELAY = 1 << 4, // delay importing resource until later, for example when proper flags can be determined
};
// Load a resource
+31 -11
View File
@@ -400,23 +400,43 @@ namespace wi::scene
}
return FILTER_TRANSPARENT;
}
void MaterialComponent::CreateRenderData()
wi::resourcemanager::Flags MaterialComponent::GetTextureSlotResourceFlags(TEXTURESLOT slot)
{
wi::resourcemanager::Flags flags = wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA;
if (!IsPreferUncompressedTexturesEnabled())
{
flags |= wi::resourcemanager::Flags::IMPORT_BLOCK_COMPRESSED;
}
switch (slot)
{
case NORMALMAP:
case CLEARCOATNORMALMAP:
flags |= wi::resourcemanager::Flags::IMPORT_NORMALMAP;
break;
default:
break;
}
return flags;
}
void MaterialComponent::CreateRenderData(bool force_recreate)
{
if (force_recreate)
{
for (uint32_t slot = 0; slot < TEXTURESLOT_COUNT; ++slot)
{
auto& textureslot = textures[slot];
if (textureslot.resource.IsValid())
{
textureslot.resource.SetOutdated();
}
}
}
for (uint32_t slot = 0; slot < TEXTURESLOT_COUNT; ++slot)
{
auto& textureslot = textures[slot];
if (!textureslot.name.empty())
{
wi::resourcemanager::Flags flags = wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA;
switch (slot)
{
case NORMALMAP:
case CLEARCOATNORMALMAP:
flags |= wi::resourcemanager::Flags::IMPORT_NORMALMAP;
break;
default:
break;
}
wi::resourcemanager::Flags flags = GetTextureSlotResourceFlags(TEXTURESLOT(slot));
textureslot.resource = wi::resourcemanager::Load(textureslot.name, flags);
}
}
+9 -4
View File
@@ -120,6 +120,7 @@ namespace wi::scene
DISABLE_RECEIVE_SHADOW = 1 << 10,
DOUBLE_SIDED = 1 << 11,
OUTLINE = 1 << 12,
PREFER_UNCOMPRESSED_TEXTURES = 1 << 13,
};
uint32_t _flags = CAST_SHADOW;
@@ -262,8 +263,9 @@ namespace wi::scene
inline bool IsOcclusionEnabled_Primary() const { return _flags & OCCLUSION_PRIMARY; }
inline bool IsOcclusionEnabled_Secondary() const { return _flags & OCCLUSION_SECONDARY; }
inline bool IsCustomShader() const { return customShaderID >= 0; }
inline bool IsDoubleSided() const { return _flags & DOUBLE_SIDED; }
inline bool IsOutlineEnabled() const { return _flags & OUTLINE; }
inline bool IsDoubleSided() const { return _flags & DOUBLE_SIDED; }
inline bool IsOutlineEnabled() const { return _flags & OUTLINE; }
inline bool IsPreferUncompressedTexturesEnabled() const { return _flags & PREFER_UNCOMPRESSED_TEXTURES; }
inline void SetBaseColor(const XMFLOAT4& value) { SetDirty(); baseColor = value; }
inline void SetSpecularColor(const XMFLOAT4& value) { SetDirty(); specularColor = value; }
@@ -302,6 +304,7 @@ namespace wi::scene
inline void DisableCustomShader() { customShaderID = -1; }
inline void SetDoubleSided(bool value = true) { if (value) { _flags |= DOUBLE_SIDED; } else { _flags &= ~DOUBLE_SIDED; } }
inline void SetOutlineEnabled(bool value = true) { if (value) { _flags |= OUTLINE; } else { _flags &= ~OUTLINE; } }
inline void SetPreferUncompressedTexturesEnabled(bool value = true) { if (value) { _flags |= PREFER_UNCOMPRESSED_TEXTURES; } else { _flags &= ~PREFER_UNCOMPRESSED_TEXTURES; } CreateRenderData(true); }
// The MaterialComponent will be written to ShaderMaterial (a struct that is optimized for GPU use)
void WriteShaderMaterial(ShaderMaterial* dest) const;
@@ -313,8 +316,10 @@ namespace wi::scene
// Returns the bitwise OR of all the wi::enums::FILTER flags applicable to this material
uint32_t GetFilterMask() const;
// Create constant buffer and texture resources for GPU
void CreateRenderData();
wi::resourcemanager::Flags GetTextureSlotResourceFlags(TEXTURESLOT slot);
// Create texture resources for GPU
void CreateRenderData(bool force_recreate = false);
void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
};
+19
View File
@@ -2033,6 +2033,25 @@ namespace wi::scene
ddgi.Serialize(archive);
}
wi::jobsystem::Wait(seri.ctx); // This is needed before emitter material fixup that is below, because material CreateRenderDatas might be pending!
// Fixup old emittedparticle distortion basecolor slot -> normalmap slot
if (archive.GetVersion() < 89)
{
for (size_t i = 0; i < emitters.GetCount(); ++i)
{
if (emitters[i].shaderType != EmittedParticleSystem::PARTICLESHADERTYPE::SOFT_DISTORTION)
continue;
Entity entity = emitters.GetEntity(i);
MaterialComponent* material = materials.GetComponent(entity);
if (material != nullptr)
{
material->textures[NORMALMAP] = std::move(material->textures[BASECOLORMAP]);
material->CreateRenderData(true);
}
}
}
wi::backlog::post("Scene serialize took " + std::to_string(timer.elapsed_seconds()) + " sec");
}
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 71;
// minor bug fixes, alterations, refactors, updates
const int revision = 213;
const int revision = 214;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);
+27
View File
@@ -510,6 +510,33 @@ OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR
SOFTWARE.
###############################################################################################################################
Compressonator: https://github.com/GPUOpen-Tools/compressonator
//===============================================================================
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//===============================================================================
###############################################################################################################################
pugixml: https://github.com/zeux/pugixml