diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md
index 4dfe71a10..cbd927e9f 100644
--- a/Content/Documentation/ScriptingAPI-Documentation.md
+++ b/Content/Documentation/ScriptingAPI-Documentation.md
@@ -610,9 +610,13 @@ This is the main entry point and manages the lifetime of the application. Even t
- SetFrameSkip(bool enabled) -- enable/disable frame skipping in fixed update
- SetTargetFrameRate(float fps) -- set target frame rate for fixed update and variable rate update when frame rate is locked
- SetFrameRateLock(bool enabled) -- if enabled, variable rate update will use a fixed delta time
-- SetInfoDisplay(bool active)
-- SetWatermarkDisplay(bool active)
-- SetFPSDisplay(bool active)
+- SetInfoDisplay(bool active) -- if enabled, information display will be visible in the top left corner of the application
+- SetWatermarkDisplay(bool active) -- toggle display of engine watermark, version number, etc. if info display is enabled
+- SetFPSDisplay(bool active) -- toggle display of frame rate if info display is enabled
+- SetResolutionDisplay(bool active) -- toggle display of resolution if info display is enabled
+- SetLogicalSizeDisplay(bool active) -- toggle display of logical size of canvas if info display is enabled
+- SetPipelineCountDisplay(bool active) -- toggle display of active graphics pipeline count if info display is enabled
+- SetHeapAllocationCountDisplay(bool active) -- toggle display of heap allocation statistics if info display is enabled
- GetCanvas() : Canvas canvas
- [outer]SetProfilerEnabled(bool enabled)
diff --git a/Content/Documentation/WickedEngine-Documentation.md b/Content/Documentation/WickedEngine-Documentation.md
index 11145a9a2..0709c76dc 100644
--- a/Content/Documentation/WickedEngine-Documentation.md
+++ b/Content/Documentation/WickedEngine-Documentation.md
@@ -1107,7 +1107,7 @@ The controller force feedback features that might be supported. Can be provided
### Touch
A touch contact point. Currently it is supported in UWP (Universal Windows Platform) applications.
- GetTouches
-Get a std::vector containing current Touch contact points
+Get a vector containing current Touch contact points
### wiXInput
[[Header]](../../WickedEngine/wiXInput.h) [[Cpp]](../../WickedEngine/wiXInput.cpp)
@@ -1261,6 +1261,7 @@ This is the place for tools that use engine-level systems
### wiBackLog
[[Header]](../../WickedEngine/wiBacklog.h) [[Cpp]](../../WickedEngine/wiBackLog.cpp)
Used to log any messages by any system, from any thread. It can draw itself to the screen. It can execute Lua scripts.
+If there was a `wiBackLog::LogLevel::Error` or higher severity message posted on the backlog, the contents of the log will be saved to the temporary user directory as wiBackLog.txt.
### wiProfiler
[[Header]](../../WickedEngine/wiProfiler.h) [[Cpp]](../../WickedEngine/wiProfiler.cpp)
Used to time specific ranges in execution. Support CPU and GPU timing. Can write the result to the screen as simple text at this time.
diff --git a/Editor/AnimationWindow.cpp b/Editor/AnimationWindow.cpp
index d16cdcf21..27d0ad65b 100644
--- a/Editor/AnimationWindow.cpp
+++ b/Editor/AnimationWindow.cpp
@@ -2,8 +2,6 @@
#include "AnimationWindow.h"
#include "Editor.h"
-#include
-
using namespace wiECS;
using namespace wiScene;
diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp
index 7111b98e8..22785aa94 100644
--- a/Editor/Editor.cpp
+++ b/Editor/Editor.cpp
@@ -5,7 +5,7 @@
#include "ModelImporter.h"
#include "Translator.h"
-#include
+#include
#include
#include
#include
@@ -680,19 +680,24 @@ void EditorComponent::Load()
saveButton.SetColor(wiColor(0, 255, 140, 255), wiWidget::WIDGETSTATE::FOCUS);
saveButton.OnClick([&](wiEventArgs args) {
+ const bool dump_to_header = saveModeComboBox.GetSelected() == 2;
+
wiHelper::FileDialogParams params;
params.type = wiHelper::FileDialogParams::SAVE;
- params.description = "Wicked Scene";
- params.extensions.push_back("wiscene");
- wiHelper::FileDialog(params, [this](std::string fileName) {
+ if (dump_to_header)
+ {
+ params.description = "C++ header (.h)";
+ params.extensions.push_back("h");
+ }
+ else
+ {
+ params.description = "Wicked Scene (.wiscene)";
+ params.extensions.push_back("wiscene");
+ }
+ wiHelper::FileDialog(params, [=](std::string fileName) {
wiEvent::Subscribe_Once(SYSTEM_EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
- std::string filename = fileName;
- std::string extension = wiHelper::GetExtensionFromFileName(filename);
- if (extension.compare("wiscene"))
- {
- filename += ".wiscene";
- }
- wiArchive archive(filename, false);
+ std::string filename = wiHelper::ReplaceExtension(fileName, params.extensions.front());
+ wiArchive archive = dump_to_header ? wiArchive() : wiArchive(filename, false);
if (archive.IsOpen())
{
Scene& scene = wiScene::GetScene();
@@ -702,6 +707,11 @@ void EditorComponent::Load()
scene.Serialize(archive);
+ if (dump_to_header)
+ {
+ archive.SaveHeaderFile(filename, wiHelper::RemoveExtension(wiHelper::GetFileNameFromPath(filename)));
+ }
+
ResetHistory();
}
else
@@ -853,36 +863,36 @@ void EditorComponent::Load()
GetGUI().AddWidget(&helpButton);
{
- std::stringstream ss("");
- ss << "Help:" << std::endl;
- ss << "Move camera: WASD, or Contoller left stick or D-pad" << std::endl;
- ss << "Look: Middle mouse button / arrow keys / controller right stick" << std::endl;
- ss << "Select: Right mouse button" << std::endl;
- ss << "Interact with water: Left mouse button when nothing is selected" << std::endl;
- ss << "Camera speed: SHIFT button or controller R2/RT" << std::endl;
- ss << "Camera up: E, down: Q" << std::endl;
- ss << "Duplicate entity: Ctrl + D" << std::endl;
- ss << "Select All: Ctrl + A" << std::endl;
- ss << "Undo: Ctrl + Z" << std::endl;
- ss << "Redo: Ctrl + Y" << std::endl;
- ss << "Copy: Ctrl + C" << std::endl;
- ss << "Paste: Ctrl + V" << std::endl;
- ss << "Delete: DELETE button" << std::endl;
- ss << "Place Instances: Ctrl + Shift + Left mouse click (place clipboard onto clicked surface)" << std::endl;
- ss << "Script Console / backlog: HOME button" << std::endl;
- ss << std::endl;
- ss << "You can find sample scenes in the models directory. Try to load one." << std::endl;
- ss << "You can also import models from .OBJ, .GLTF, .GLB files." << std::endl;
- ss << "You can find a program configuration file at Editor/config.ini" << std::endl;
- ss << "You can find sample LUA scripts in the scripts directory. Try to load one." << std::endl;
- ss << "You can find a startup script at Editor/startup.lua (this will be executed on program start)" << std::endl;
- ss << std::endl << "For questions, bug reports, feedback, requests, please open an issue at:" << std::endl;
- ss << "https://github.com/turanszkij/WickedEngine" << std::endl;
- ss << std::endl << "Devblog: https://wickedengine.net/" << std::endl;
- ss << "Discord: https://discord.gg/CFjRYmE" << std::endl;
+ std::string ss;
+ ss += "Help:\n";
+ ss += "Move camera: WASD, or Contoller left stick or D-pad\n";
+ ss += "Look: Middle mouse button / arrow keys / controller right stick\n";
+ ss += "Select: Right mouse button\n";
+ ss += "Interact with water: Left mouse button when nothing is selected\n";
+ ss += "Camera speed: SHIFT button or controller R2/RT\n";
+ ss += "Camera up: E, down: Q\n";
+ ss += "Duplicate entity: Ctrl + D\n";
+ ss += "Select All: Ctrl + A\n";
+ ss += "Undo: Ctrl + Z\n";
+ ss += "Redo: Ctrl + Y\n";
+ ss += "Copy: Ctrl + C\n";
+ ss += "Paste: Ctrl + V\n";
+ ss += "Delete: DELETE button\n";
+ ss += "Place Instances: Ctrl + Shift + Left mouse click (place clipboard onto clicked surface)\n";
+ ss += "Script Console / backlog: HOME button\n";
+ ss += "\n";
+ ss += "You can find sample scenes in the models directory. Try to load one.\n";
+ ss += "You can also import models from .OBJ, .GLTF, .GLB files.\n";
+ ss += "You can find a program configuration file at Editor/config.ini\n";
+ ss += "You can find sample LUA scripts in the scripts directory. Try to load one.\n";
+ ss += "You can find a startup script at Editor/startup.lua (this will be executed on program start)\n";
+ ss += "\nFor questions, bug reports, feedback, requests, please open an issue at:\n";
+ ss += "https://github.com/turanszkij/WickedEngine\n";
+ ss += "\nDevblog: https://wickedengine.net/\n";
+ ss += "Discord: https://discord.gg/CFjRYmE\n";
helpLabel.Create("HelpLabel");
- helpLabel.SetText(ss.str());
+ helpLabel.SetText(ss);
helpLabel.SetVisible(false);
GetGUI().AddWidget(&helpLabel);
}
@@ -965,7 +975,8 @@ void EditorComponent::Load()
saveModeComboBox.SetColor(wiColor(0, 255, 140, 255), wiWidget::WIDGETSTATE::FOCUS);
saveModeComboBox.AddItem("Embed resources", wiResourceManager::MODE_ALLOW_RETAIN_FILEDATA);
saveModeComboBox.AddItem("No embedding", wiResourceManager::MODE_ALLOW_RETAIN_FILEDATA_BUT_DISABLE_EMBEDDING);
- saveModeComboBox.SetTooltip("Choose whether to embed resources (textures, sounds...) in the scene file when saving, or keep them as separate files");
+ saveModeComboBox.AddItem("Dump to header", wiResourceManager::MODE_ALLOW_RETAIN_FILEDATA);
+ saveModeComboBox.SetTooltip("Choose whether to embed resources (textures, sounds...) in the scene file when saving, or keep them as separate files.\nThe Dump to header option will use embedding and create a C++ header file with byte data of the scene to be used with wiArchive serialization.");
GetGUI().AddWidget(&saveModeComboBox);
@@ -1471,7 +1482,7 @@ void EditorComponent::Update(float dt)
if (!translator.selected.empty() && wiInput::Down(wiInput::KEYBOARD_BUTTON_LSHIFT))
{
// Union selection:
- std::vector saved = translator.selected;
+ wi::vector saved = translator.selected;
translator.selected.clear();
for (const wiScene::PickResult& picked : saved)
{
@@ -1762,21 +1773,21 @@ void EditorComponent::Update(float dt)
{
pathtracer->setTargetSampleCount((int)pathTraceTargetSlider.GetValue());
- std::stringstream ss;
- ss << "Sample count: " << pathtracer->getCurrentSampleCount() << std::endl;
- ss << "Trace progress: " << int(pathtracer->getProgress() * 100) << "%" << std::endl;
+ std::string ss;
+ ss += "Sample count: " + std::to_string(pathtracer->getCurrentSampleCount()) + "\n";
+ ss += "Trace progress: " + std::to_string(int(pathtracer->getProgress() * 100)) + "%\n";
if (pathtracer->isDenoiserAvailable())
{
if (pathtracer->getDenoiserProgress() > 0)
{
- ss << "Denoiser progress: " << int(pathtracer->getDenoiserProgress() * 100) << "%" << std::endl;
+ ss += "Denoiser progress: " + std::to_string(int(pathtracer->getDenoiserProgress() * 100)) + "%\n";
}
}
else
{
- ss << "Denoiser not available" << std::endl;
+ ss += "Denoiser not available\n";
}
- pathTraceStatisticsLabel.SetText(ss.str());
+ pathTraceStatisticsLabel.SetText(ss);
}
wiProfiler::EndRange(profrange);
@@ -2500,7 +2511,7 @@ void EditorComponent::ConsumeHistoryOperation(bool undo)
{
size_t count;
archive >> count;
- std::vector deletedEntities(count);
+ wi::vector deletedEntities(count);
for (size_t i = 0; i < count; ++i)
{
archive >> deletedEntities[i];
@@ -2527,7 +2538,7 @@ void EditorComponent::ConsumeHistoryOperation(bool undo)
{
// Read selections states from archive:
- std::vector selectedBEFORE;
+ wi::vector selectedBEFORE;
size_t selectionCountBEFORE;
archive >> selectionCountBEFORE;
for (size_t i = 0; i < selectionCountBEFORE; ++i)
@@ -2542,7 +2553,7 @@ void EditorComponent::ConsumeHistoryOperation(bool undo)
selectedBEFORE.push_back(sel);
}
- std::vector selectedAFTER;
+ wi::vector selectedAFTER;
size_t selectionCountAFTER;
archive >> selectionCountAFTER;
for (size_t i = 0; i < selectionCountAFTER; ++i)
diff --git a/Editor/Editor.h b/Editor/Editor.h
index a4c7bf24f..d0a5e719b 100644
--- a/Editor/Editor.h
+++ b/Editor/Editor.h
@@ -103,8 +103,8 @@ public:
wiLabel helpLabel;
wiTreeList sceneGraphView;
- std::unordered_set scenegraphview_added_items;
- std::unordered_set scenegraphview_opened_items;
+ wi::unordered_set scenegraphview_added_items;
+ wi::unordered_set scenegraphview_opened_items;
void PushToSceneGraphView(wiECS::Entity entity, int level);
void RefreshSceneGraphView();
@@ -158,7 +158,7 @@ public:
wiArchive clipboard;
- std::vector history;
+ wi::vector history;
int historyPos = -1;
enum HistoryOperationType
{
diff --git a/Editor/EmitterWindow.cpp b/Editor/EmitterWindow.cpp
index 8741183e4..92f00f5d4 100644
--- a/Editor/EmitterWindow.cpp
+++ b/Editor/EmitterWindow.cpp
@@ -2,7 +2,7 @@
#include "EmitterWindow.h"
#include "Editor.h"
-#include
+#include
using namespace wiECS;
using namespace wiScene;
@@ -755,19 +755,18 @@ void EmitterWindow::UpdateData()
NameComponent* name = scene.names.GetComponent(entity);
NameComponent* meshName = scene.names.GetComponent(emitter->meshID);
- std::stringstream ss("");
- ss.precision(2);
- ss << "Emitter Mesh: " << (meshName != nullptr ? meshName->name : "NO EMITTER MESH") << " (" << emitter->meshID << ")" << std::endl;
- ss << "Memort Budget: " << emitter->GetMemorySizeInBytes() / 1024.0f / 1024.0f << " MB" << std::endl;
- ss << std::endl;
+ std::string ss;
+ ss += "Emitter Mesh: " + (meshName != nullptr ? meshName->name : "NO EMITTER MESH") + " (" + std::to_string(emitter->meshID) + ")\n";
+ ss += "Memort Budget: " + std::to_string(emitter->GetMemorySizeInBytes() / 1024.0f / 1024.0f) + " MB\n";
+ ss += "\n";
auto data = emitter->GetStatistics();
- ss << "Alive Particle Count = " << data.aliveCount << std::endl;
- ss << "Dead Particle Count = " << data.deadCount << std::endl;
- ss << "GPU Emit count = " << data.realEmitCount << std::endl;
- ss << "Visible after frustum culling = " << data.culledCount << std::endl;
+ ss += "Alive Particle Count = " + std::to_string(data.aliveCount) + "\n";
+ ss += "Dead Particle Count = " + std::to_string(data.deadCount) + "\n";
+ ss += "GPU Emit count = " + std::to_string(data.realEmitCount) + "\n";
+ ss += "Visible after frustum culling = " + std::to_string(data.culledCount) + "\n";
- infoLabel.SetText(ss.str());
+ infoLabel.SetText(ss);
emitterNameField.SetText(name->name);
}
diff --git a/Editor/MaterialWindow.cpp b/Editor/MaterialWindow.cpp
index 70b89efcd..8491ea309 100644
--- a/Editor/MaterialWindow.cpp
+++ b/Editor/MaterialWindow.cpp
@@ -2,8 +2,6 @@
#include "MaterialWindow.h"
#include "Editor.h"
-#include
-
using namespace wiGraphics;
using namespace wiECS;
using namespace wiScene;
diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp
index a473fee3c..38c48d97d 100644
--- a/Editor/MeshWindow.cpp
+++ b/Editor/MeshWindow.cpp
@@ -6,7 +6,7 @@
#include "meshoptimizer/meshoptimizer.h"
-#include
+#include
using namespace wiECS;
using namespace wiScene;
@@ -366,7 +366,7 @@ void MeshWindow::Create(EditorComponent* editor)
size_t index_count = mesh->indices.size();
size_t vertex_count = mesh->vertex_positions.size();
- std::vector indices(index_count);
+ wi::vector indices(index_count);
meshopt_optimizeVertexCache(indices.data(), mesh->indices.data(), index_count, vertex_count);
mesh->indices = indices;
@@ -657,25 +657,25 @@ void MeshWindow::SetEntity(Entity entity, int subset)
{
const NameComponent& name = *scene.names.GetComponent(entity);
- std::stringstream ss("");
- ss << "Mesh name: " << name.name << std::endl;
- ss << "Vertex count: " << mesh->vertex_positions.size() << std::endl;
- ss << "Index count: " << mesh->indices.size() << std::endl;
- ss << "Subset count: " << mesh->subsets.size() << std::endl;
- ss << std::endl << "Vertex buffers: ";
- if (mesh->vertexBuffer_POS.IsValid()) ss << "position; ";
- if (mesh->vertexBuffer_UV0.IsValid()) ss << "uvset_0; ";
- if (mesh->vertexBuffer_UV1.IsValid()) ss << "uvset_1; ";
- if (mesh->vertexBuffer_ATL.IsValid()) ss << "atlas; ";
- if (mesh->vertexBuffer_COL.IsValid()) ss << "color; ";
- if (mesh->vertexBuffer_PRE.IsValid()) ss << "previous_position; ";
- if (mesh->vertexBuffer_BON.IsValid()) ss << "bone; ";
- if (mesh->vertexBuffer_TAN.IsValid()) ss << "tangent; ";
- if (mesh->streamoutBuffer_POS.IsValid()) ss << "streamout_position; ";
- if (mesh->streamoutBuffer_TAN.IsValid()) ss << "streamout_tangents; ";
- if (mesh->subsetBuffer.IsValid()) ss << "subset; ";
- if (mesh->IsTerrain()) ss << std::endl << std::endl << "Terrain will use 4 blend materials and blend by vertex colors, the default one is always the subset material and uses RED vertex color channel mask, the other 3 are selectable below.";
- meshInfoLabel.SetText(ss.str());
+ std::string ss;
+ ss += "Mesh name: " + name.name + "\n";
+ ss += "Vertex count: " + std::to_string(mesh->vertex_positions.size()) + "\n";
+ ss += "Index count: " + std::to_string(mesh->indices.size()) + "\n";
+ ss += "Subset count: " + std::to_string(mesh->subsets.size()) + "\n";
+ ss += "\nVertex buffers: ";
+ if (mesh->vertexBuffer_POS.IsValid()) ss += "position; ";
+ if (mesh->vertexBuffer_UV0.IsValid()) ss += "uvset_0; ";
+ if (mesh->vertexBuffer_UV1.IsValid()) ss += "uvset_1; ";
+ if (mesh->vertexBuffer_ATL.IsValid()) ss += "atlas; ";
+ if (mesh->vertexBuffer_COL.IsValid()) ss += "color; ";
+ if (mesh->vertexBuffer_PRE.IsValid()) ss += "previous_position; ";
+ if (mesh->vertexBuffer_BON.IsValid()) ss += "bone; ";
+ if (mesh->vertexBuffer_TAN.IsValid()) ss += "tangent; ";
+ if (mesh->streamoutBuffer_POS.IsValid()) ss += "streamout_position; ";
+ if (mesh->streamoutBuffer_TAN.IsValid()) ss += "streamout_tangents; ";
+ if (mesh->subsetBuffer.IsValid()) ss += "subset; ";
+ if (mesh->IsTerrain()) ss += "\n\nTerrain will use 4 blend materials and blend by vertex colors, the default one is always the subset material and uses RED vertex color channel mask, the other 3 are selectable below.";
+ meshInfoLabel.SetText(ss);
terrainCheckBox.SetCheck(mesh->IsTerrain());
diff --git a/Editor/ModelImporter_GLTF.cpp b/Editor/ModelImporter_GLTF.cpp
index 3c0a677ab..29f8fd9c3 100644
--- a/Editor/ModelImporter_GLTF.cpp
+++ b/Editor/ModelImporter_GLTF.cpp
@@ -5,16 +5,16 @@
#include "Utility/stb_image.h"
+#include
+#include
+#include
+
#define TINYGLTF_IMPLEMENTATION
#define TINYGLTF_NO_FS
#define TINYGLTF_NO_STB_IMAGE
#define TINYGLTF_NO_STB_IMAGE_WRITE
#include "tiny_gltf.h"
-#include
-#include
-#include
-
using namespace wiGraphics;
using namespace wiScene;
using namespace wiECS;
@@ -79,7 +79,7 @@ namespace tinygltf
#endif
}
- bool ReadWholeFile(std::vector* out, std::string* err,
+ bool ReadWholeFile(wi::vector* out, std::string* err,
const std::string& filepath, void*) {
return wiHelper::FileRead(filepath, *out);
}
@@ -98,12 +98,12 @@ namespace tinygltf
if (image->uri.empty())
{
// Force some image resource name:
- std::stringstream ss;
+ std::string ss;
do {
- ss.str("");
- ss << "gltfimport_" << wiRandom::getRandom(INT_MAX) << ".png";
- } while (wiResourceManager::Contains(ss.str())); // this is to avoid overwriting an existing imported image
- image->uri = ss.str();
+ ss.clear();
+ ss += "gltfimport_" + std::to_string(wiRandom::getRandom(std::numeric_limits::max())) + ".png";
+ } while (wiResourceManager::Contains(ss)); // this is to avoid overwriting an existing imported image
+ image->uri = ss;
}
auto resource = wiResourceManager::Load(
@@ -142,7 +142,7 @@ struct LoaderState
{
tinygltf::Model gltfModel;
Scene* scene;
- std::unordered_map entityMap; // node -> entity
+ wi::unordered_map entityMap; // node -> entity
};
// Recursively loads nodes and resolves hierarchy:
@@ -278,7 +278,7 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
LoaderState state;
state.scene = &scene;
- std::vector filedata;
+ wi::vector filedata;
ret = wiHelper::FileRead(fileName, filedata);
if (ret)
@@ -718,7 +718,7 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
}
else
{
- wiBackLog::post("[KHR_materials_specular warning] specularTexture must be either in surfaceMap.a or specularColorTexture.a! specularTexture discarded!");
+ wiBackLog::post("[KHR_materials_specular warning] specularTexture must be either in surfaceMap.a or specularColorTexture.a! specularTexture discarded!", wiBackLog::LogLevel::Warning);
}
}
if (ext_specular->second.Has("specularColorTexture"))
diff --git a/Editor/ModelImporter_OBJ.cpp b/Editor/ModelImporter_OBJ.cpp
index 64b45a4c9..24f9edd5b 100644
--- a/Editor/ModelImporter_OBJ.cpp
+++ b/Editor/ModelImporter_OBJ.cpp
@@ -5,6 +5,7 @@
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
+#include
#include
#include
@@ -26,7 +27,7 @@ public:
: m_mtlBaseDir(mtl_basedir) {}
virtual ~MaterialFileReader() {}
virtual bool operator()(const std::string& matId,
- std::vector* materials,
+ wi::vector* materials,
std::map* matMap, std::string* err)
{
std::string filepath;
@@ -38,13 +39,13 @@ public:
filepath = matId;
}
- std::vector filedata;
+ wi::vector filedata;
if (!wiHelper::FileRead(filepath, filedata))
{
- std::stringstream ss;
- ss << "WARN: Material file [ " << filepath << " ] not found." << std::endl;
+ std::string ss;
+ ss += "WARN: Material file [ " + filepath + " ] not found.\n";
if (err) {
- (*err) += ss.str();
+ (*err) += ss;
}
return false;
}
@@ -77,11 +78,11 @@ void ImportModel_OBJ(const std::string& fileName, Scene& scene)
std::string name = wiHelper::GetFileNameFromPath(fileName);
tinyobj::attrib_t obj_attrib;
- std::vector obj_shapes;
- std::vector obj_materials;
+ wi::vector obj_shapes;
+ wi::vector obj_materials;
std::string obj_errors;
- std::vector filedata;
+ wi::vector filedata;
bool success = wiHelper::FileRead(fileName, filedata);
if (success)
@@ -98,7 +99,7 @@ void ImportModel_OBJ(const std::string& fileName, Scene& scene)
if (!obj_errors.empty())
{
- wiBackLog::post(obj_errors.c_str());
+ wiBackLog::post(obj_errors, wiBackLog::LogLevel::Error);
}
if (success)
@@ -108,7 +109,7 @@ void ImportModel_OBJ(const std::string& fileName, Scene& scene)
scene.names.Create(rootEntity) = name;
// Load material library:
- std::vector materialLibrary = {};
+ wi::vector materialLibrary = {};
for (auto& obj_material : obj_materials)
{
Entity materialEntity = scene.Entity_CreateMaterial(obj_material.name);
@@ -168,8 +169,8 @@ void ImportModel_OBJ(const std::string& fileName, Scene& scene)
object.meshID = meshEntity;
- std::unordered_map registered_materialIndices = {};
- std::unordered_map uniqueVertices = {};
+ wi::unordered_map registered_materialIndices = {};
+ wi::unordered_map uniqueVertices = {};
for (size_t i = 0; i < shape.mesh.indices.size(); i += 3)
{
diff --git a/Editor/ObjectWindow.cpp b/Editor/ObjectWindow.cpp
index 60b643645..dabb1f8a2 100644
--- a/Editor/ObjectWindow.cpp
+++ b/Editor/ObjectWindow.cpp
@@ -5,9 +5,7 @@
#include "xatlas.h"
-#include
-#include
-#include
+#include
using namespace wiECS;
using namespace wiScene;
@@ -115,15 +113,15 @@ static Atlas_Dim GenerateMeshAtlas(MeshComponent& meshcomponent, uint32_t resolu
// Note: we must recreate all vertex buffers, because the index buffer will be different (the atlas could have removed shared vertices)
meshcomponent.indices.clear();
meshcomponent.indices.resize(mesh.indexCount);
- std::vector positions(mesh.vertexCount);
- std::vector atlas(mesh.vertexCount);
- std::vector normals;
- std::vector tangents;
- std::vector uvset_0;
- std::vector uvset_1;
- std::vector colors;
- std::vector boneindices;
- std::vector boneweights;
+ wi::vector positions(mesh.vertexCount);
+ wi::vector atlas(mesh.vertexCount);
+ wi::vector normals;
+ wi::vector tangents;
+ wi::vector uvset_0;
+ wi::vector uvset_1;
+ wi::vector colors;
+ wi::vector boneindices;
+ wi::vector boneweights;
if (!meshcomponent.vertex_normals.empty())
{
normals.resize(mesh.vertexCount);
@@ -651,8 +649,8 @@ void ObjectWindow::Create(EditorComponent* editor)
};
UV_GEN_TYPE gen_type = (UV_GEN_TYPE)lightmapSourceUVSetComboBox.GetSelected();
- std::unordered_set gen_objects;
- std::unordered_map gen_meshes;
+ wi::unordered_set gen_objects;
+ wi::unordered_map gen_meshes;
for (auto& x : this->editor->translator.selected)
{
diff --git a/Editor/PaintToolWindow.cpp b/Editor/PaintToolWindow.cpp
index e8ae7bf20..00ca9ccf3 100644
--- a/Editor/PaintToolWindow.cpp
+++ b/Editor/PaintToolWindow.cpp
@@ -3,7 +3,6 @@
#include "PaintToolWindow.h"
#include "shaders/ShaderInterop_Renderer.h"
-#include
#include
using namespace wiECS;
@@ -179,7 +178,7 @@ void PaintToolWindow::Create(EditorComponent* editor)
uint64_t sel = textureSlotComboBox.GetItemUserData(textureSlotComboBox.GetSelected());
- std::vector texturefiledata;
+ wi::vector texturefiledata;
if (wiHelper::saveTextureToMemoryFile(editTexture, "PNG", texturefiledata))
{
material->textures[sel].resource->filedata = texturefiledata;
@@ -548,7 +547,7 @@ void PaintToolWindow::Update(float dt)
size_t ind;
float affection;
};
- static std::vector paintindices;
+ static wi::vector paintindices;
paintindices.clear();
paintindices.reserve(mesh->vertex_positions.size());
diff --git a/Editor/PaintToolWindow.h b/Editor/PaintToolWindow.h
index c34563601..4708a97e4 100644
--- a/Editor/PaintToolWindow.h
+++ b/Editor/PaintToolWindow.h
@@ -10,7 +10,7 @@ class PaintToolWindow : public wiWindow
bool history_needs_recording_start = false;
bool history_needs_recording_end = false;
size_t history_textureIndex = 0;
- std::vector history_textures; // we'd like to keep history textures in GPU memory to avoid GPU readback
+ wi::vector history_textures; // we'd like to keep history textures in GPU memory to avoid GPU readback
wiGraphics::Texture GetEditTextureSlot(const wiScene::MaterialComponent& material, int* uvset = nullptr);
void ReplaceEditTextureSlot(wiScene::MaterialComponent& material, const wiGraphics::Texture& texture);
public:
diff --git a/Editor/SoundWindow.cpp b/Editor/SoundWindow.cpp
index 46fd7eb43..244f73db2 100644
--- a/Editor/SoundWindow.cpp
+++ b/Editor/SoundWindow.cpp
@@ -3,8 +3,6 @@
#include "wiAudio.h"
#include "Editor.h"
-#include
-
using namespace wiGraphics;
using namespace wiECS;
using namespace wiScene;
diff --git a/Editor/Translator.h b/Editor/Translator.h
index 0fdbf25fd..76fea0515 100644
--- a/Editor/Translator.h
+++ b/Editor/Translator.h
@@ -1,8 +1,7 @@
#pragma once
#include "CommonInclude.h"
#include "wiCanvas.h"
-
-#include
+#include "wiVector.h"
class Translator
{
@@ -24,7 +23,7 @@ public:
void PostTranslate();
wiScene::TransformComponent transform;
- std::vector selected;
+ wi::vector selected;
bool enabled = false;
diff --git a/Editor/WeatherWindow.cpp b/Editor/WeatherWindow.cpp
index 5ebbd6bb1..8458b1e2c 100644
--- a/Editor/WeatherWindow.cpp
+++ b/Editor/WeatherWindow.cpp
@@ -2,9 +2,6 @@
#include "WeatherWindow.h"
#include "Editor.h"
-#include
-#include
-
using namespace wiECS;
using namespace wiScene;
using namespace wiGraphics;
@@ -561,7 +558,7 @@ void WeatherWindow::Create(EditorComponent* editor)
Scene& scene = wiScene::GetScene();
- std::unordered_map> conv;
+ wi::unordered_map> conv;
for (uint32_t i = 0; i < scene.materials.GetCount(); ++i)
{
MaterialComponent& material = scene.materials[i];
@@ -583,7 +580,7 @@ void WeatherWindow::Create(EditorComponent* editor)
if (wiHelper::saveTextureToMemory(x.second->texture, x.second->filedata))
{
wiJobSystem::Execute(ctx, [&](wiJobArgs args) {
- std::vector filedata_ktx2;
+ wi::vector filedata_ktx2;
if (wiHelper::saveTextureToMemoryFile(x.second->filedata, x.second->texture.desc, "KTX2", filedata_ktx2))
{
x.second = wiResourceManager::Load(x.first, wiResourceManager::IMPORT_RETAIN_FILEDATA, filedata_ktx2.data(), filedata_ktx2.size());
diff --git a/Editor/main_SDL2.cpp b/Editor/main_SDL2.cpp
index 086b8a587..09df13dec 100644
--- a/Editor/main_SDL2.cpp
+++ b/Editor/main_SDL2.cpp
@@ -111,20 +111,23 @@ int sdl_loop(Editor &editor)
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
editor.is_window_active = true;
- std::thread([] {
- wiBackLog::post("[Shader check] Started...");
- if (wiShaderCompiler::CheckRegisteredShadersOutdated())
- {
- wiBackLog::post("[Shader check] Changes detected, initiating reload...");
- wiEvent::Subscribe_Once(SYSTEM_EVENT_THREAD_SAFE_POINT, [](uint64_t userdata) {
- wiRenderer::ReloadShaders();
- });
- }
- else
- {
- wiBackLog::post("[Shader check] All up to date");
- }
- }).detach();
+ if (wiShaderCompiler::GetRegisteredShaderCount() > 0)
+ {
+ std::thread([] {
+ wiBackLog::post("[Shader check] Started checking " + std::to_string(wiShaderCompiler::GetRegisteredShaderCount()) + " registered shaders for changes...");
+ if (wiShaderCompiler::CheckRegisteredShadersOutdated())
+ {
+ wiBackLog::post("[Shader check] Changes detected, initiating reload...");
+ wiEvent::Subscribe_Once(SYSTEM_EVENT_THREAD_SAFE_POINT, [](uint64_t userdata) {
+ wiRenderer::ReloadShaders();
+ });
+ }
+ else
+ {
+ wiBackLog::post("[Shader check] All up to date");
+ }
+ }).detach();
+ }
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
editor.is_window_active = false;
diff --git a/Editor/main_Windows.cpp b/Editor/main_Windows.cpp
index d414f052e..44bc47cbb 100644
--- a/Editor/main_Windows.cpp
+++ b/Editor/main_Windows.cpp
@@ -3,6 +3,7 @@
#include "Editor.h"
#include
+#include
#define MAX_LOADSTRING 100
@@ -247,20 +248,23 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
break;
case WM_SETFOCUS:
editor.is_window_active = true;
- std::thread([] {
- wiBackLog::post("[Shader check] Started...");
- if (wiShaderCompiler::CheckRegisteredShadersOutdated())
- {
- wiBackLog::post("[Shader check] Changes detected, initiating reload...");
- wiEvent::Subscribe_Once(SYSTEM_EVENT_THREAD_SAFE_POINT, [](uint64_t userdata) {
- wiRenderer::ReloadShaders();
- });
- }
- else
- {
- wiBackLog::post("[Shader check] All up to date");
- }
- }).detach();
+ if (wiShaderCompiler::GetRegisteredShaderCount() > 0)
+ {
+ std::thread([] {
+ wiBackLog::post("[Shader check] Started checking " + std::to_string(wiShaderCompiler::GetRegisteredShaderCount()) + " registered shaders for changes...");
+ if (wiShaderCompiler::CheckRegisteredShadersOutdated())
+ {
+ wiBackLog::post("[Shader check] Changes detected, initiating reload...");
+ wiEvent::Subscribe_Once(SYSTEM_EVENT_THREAD_SAFE_POINT, [](uint64_t userdata) {
+ wiRenderer::ReloadShaders();
+ });
+ }
+ else
+ {
+ wiBackLog::post("[Shader check] All up to date");
+ }
+ }).detach();
+ }
break;
case WM_PAINT:
{
diff --git a/Example_ImGui/Example_ImGui.cpp b/Example_ImGui/Example_ImGui.cpp
index 9f55b4484..0b62e37a0 100644
--- a/Example_ImGui/Example_ImGui.cpp
+++ b/Example_ImGui/Example_ImGui.cpp
@@ -10,8 +10,6 @@
#include "ImGui/imgui_impl_sdl.h"
#endif
-#include
-#include
#include
#include
diff --git a/Tests/Tests.cpp b/Tests/Tests.cpp
index 7eb5ebdcb..7371633ed 100644
--- a/Tests/Tests.cpp
+++ b/Tests/Tests.cpp
@@ -2,9 +2,9 @@
#include "Tests.h"
#include
-#include
#include
#include
+#include
using namespace wiECS;
using namespace wiScene;
@@ -120,6 +120,7 @@ void TestsRenderer::Load()
testSelector.AddItem("Controller Test");
testSelector.AddItem("Inverse Kinematics");
testSelector.AddItem("65k Instances");
+ testSelector.AddItem("unordered_map perf");
testSelector.SetMaxVisibleItemCount(10);
testSelector.OnSelect([=](wiEventArgs args) {
@@ -293,6 +294,10 @@ void TestsRenderer::Load()
}
break;
+ case 19:
+ RunUnorderedMapTest();
+ break;
+
default:
assert(0);
break;
@@ -403,13 +408,13 @@ void TestsRenderer::RunJobSystemTest()
// This will simulate going over a big dataset first in a simple loop, then with the Job System and compare timings
uint32_t itemCount = 1000000;
- std::stringstream ss("");
- ss << "Job System performance test:" << std::endl;
- ss << "You can find out more in Tests.cpp, RunJobSystemTest() function." << std::endl << std::endl;
+ std::string ss;
+ ss += "Job System performance test:\n";
+ ss += "You can find out more in Tests.cpp, RunJobSystemTest() function.\n\n";
- ss << "wiJobSystem was created with " << wiJobSystem::GetThreadCount() << " worker threads." << std::endl << std::endl;
+ ss += "wiJobSystem was created with " + std::to_string(wiJobSystem::GetThreadCount()) + " worker threads.\n\n";
- ss << "1) Execute() test:" << std::endl;
+ ss += "1) Execute() test:\n";
// Serial test
{
@@ -419,7 +424,7 @@ void TestsRenderer::RunJobSystemTest()
wiHelper::Spin(100);
wiHelper::Spin(100);
double time = timer.elapsed();
- ss << "Serial took " << time << " milliseconds" << std::endl;
+ ss += "Serial took " + std::to_string(time) + " milliseconds\n";
}
// Execute test
{
@@ -430,38 +435,37 @@ void TestsRenderer::RunJobSystemTest()
wiJobSystem::Execute(ctx, [](wiJobArgs args){ wiHelper::Spin(100); });
wiJobSystem::Wait(ctx);
double time = timer.elapsed();
- ss << "wiJobSystem::Execute() took " << time << " milliseconds" << std::endl;
+ ss += "wiJobSystem::Execute() took " + std::to_string(time) + " milliseconds\n";
}
- ss << std::endl;
- ss << "2) Dispatch() test:" << std::endl;
+ ss += "\n2) Dispatch() test:\n";
// Simple loop test:
{
- std::vector dataSet(itemCount);
+ wi::vector dataSet(itemCount);
timer.record();
for (uint32_t i = 0; i < itemCount; ++i)
{
dataSet[i].UpdateCamera();
}
double time = timer.elapsed();
- ss << "Simple loop took " << time << " milliseconds" << std::endl;
+ ss += "Simple loop took " + std::to_string(time) + " milliseconds\n";
}
// Dispatch test:
{
- std::vector dataSet(itemCount);
+ wi::vector dataSet(itemCount);
timer.record();
wiJobSystem::Dispatch(ctx, itemCount, 1000, [&](wiJobArgs args) {
dataSet[args.jobIndex].UpdateCamera();
});
wiJobSystem::Wait(ctx);
double time = timer.elapsed();
- ss << "wiJobSystem::Dispatch() took " << time << " milliseconds" << std::endl;
+ ss += "wiJobSystem::Dispatch() took " + std::to_string(time) + " milliseconds\n";
}
static wiSpriteFont font;
- font = wiSpriteFont(ss.str());
+ font = wiSpriteFont(ss);
font.params.posX = GetLogicalWidth() / 2;
font.params.posY = GetLogicalHeight() / 2;
font.params.h_align = WIFALIGN_CENTER;
@@ -509,7 +513,7 @@ void TestsRenderer::RunFontTest()
font_aligned2.SetText("Right aligned, purple shadow");
AddFont(&font_aligned2);
- std::stringstream ss("");
+ std::string ss;
std::ifstream file("font_test.txt");
if (file.is_open())
{
@@ -517,7 +521,7 @@ void TestsRenderer::RunFontTest()
{
std::string s;
file >> s;
- ss << s << "\t";
+ ss += s + "\t";
}
}
static wiSpriteFont font_japanese;
@@ -527,7 +531,7 @@ void TestsRenderer::RunFontTest()
font_japanese.params.shadowColor = wiColor::Transparent();
font_japanese.params.h_align = WIFALIGN_CENTER;
font_japanese.params.size = 34;
- font_japanese.SetText(ss.str());
+ font_japanese.SetText(ss);
AddFont(&font_japanese);
static wiSpriteFont font_colored;
@@ -926,3 +930,55 @@ void TestsRenderer::RunNetworkTest()
font.params.size = 24;
AddFont(&font);
}
+void TestsRenderer::RunUnorderedMapTest()
+{
+ wiTimer timer;
+
+ const size_t elements = 1000000;
+#define shuffle(i) (i * 345734667877) % 98787546343
+
+ std::string ss = "Unordered map test for " + std::to_string(elements) + " elements:";
+
+ std::unordered_map std_map;
+ {
+ timer.record();
+ for (size_t i = 0; i < elements; ++i)
+ {
+ std_map[shuffle(i)] = i;
+ }
+ ss += "\n\nstd::unordered_map insertion: " + std::to_string(timer.elapsed_milliseconds()) + " ms\n";
+
+ timer.record();
+ for (size_t i = 0; i < std_map.size(); ++i)
+ {
+ std_map[shuffle(i)] = 0;
+ }
+ ss += "std::unordered_map access: " + std::to_string(timer.elapsed_milliseconds()) + " ms";
+ }
+
+ wi::unordered_map wi_map;
+ {
+ timer.record();
+ for (size_t i = 0; i < elements; ++i)
+ {
+ wi_map[shuffle(i)] = i;
+ }
+ ss += "\n\nwi::unordered_map insertion: " + std::to_string(timer.elapsed_milliseconds()) + " ms\n";
+
+ timer.record();
+ for (size_t i = 0; i < wi_map.size(); ++i)
+ {
+ wi_map[shuffle(i)] = 0;
+ }
+ ss += "wi::unordered_map access: " + std::to_string(timer.elapsed_milliseconds()) + " ms";
+ }
+
+ static wiSpriteFont font;
+ font = wiSpriteFont(ss);
+ font.params.posX = GetLogicalWidth() / 2;
+ font.params.posY = GetLogicalHeight() / 2;
+ font.params.h_align = WIFALIGN_CENTER;
+ font.params.v_align = WIFALIGN_CENTER;
+ font.params.size = 24;
+ this->AddFont(&font);
+}
diff --git a/Tests/Tests.h b/Tests/Tests.h
index 654fc1a6d..61f1abe1a 100644
--- a/Tests/Tests.h
+++ b/Tests/Tests.h
@@ -16,6 +16,7 @@ public:
void RunFontTest();
void RunSpriteTest();
void RunNetworkTest();
+ void RunUnorderedMapTest();
};
class Tests : public MainComponent
diff --git a/WickedEngine/LoadingScreen.h b/WickedEngine/LoadingScreen.h
index d43190675..08a6b5c5b 100644
--- a/WickedEngine/LoadingScreen.h
+++ b/WickedEngine/LoadingScreen.h
@@ -2,6 +2,7 @@
#include "RenderPath2D.h"
#include "wiColor.h"
#include "wiJobSystem.h"
+#include "wiVector.h"
#include
@@ -12,7 +13,7 @@ class LoadingScreen :
{
private:
wiJobSystem::context ctx;
- std::vector> tasks;
+ wi::vector> tasks;
std::function finish;
public:
diff --git a/WickedEngine/MainComponent.cpp b/WickedEngine/MainComponent.cpp
index 3b8adff42..9d6511fe0 100644
--- a/WickedEngine/MainComponent.cpp
+++ b/WickedEngine/MainComponent.cpp
@@ -19,13 +19,14 @@
#include "wiGraphicsDevice_DX12.h"
#include "wiGraphicsDevice_Vulkan.h"
-#include
+#include
#include
#include
#include
#include
std::atomic number_of_heap_allocations{ 0 };
+std::atomic size_of_heap_allocations{ 0 };
using namespace wiGraphics;
@@ -218,6 +219,8 @@ void MainComponent::Update(float dt)
wiLua::SetDeltaTime(double(dt));
wiLua::Update();
+ wiBackLog::Update(canvas, dt);
+
if (GetActivePath() != nullptr)
{
GetActivePath()->Update(dt);
@@ -229,7 +232,6 @@ void MainComponent::Update(float dt)
void MainComponent::FixedUpdate()
{
- wiBackLog::Update(canvas);
wiLua::FixedUpdate();
if (GetActivePath() != nullptr)
@@ -274,71 +276,73 @@ void MainComponent::Compose(CommandList cmd)
// Draw the information display
if (infoDisplay.active)
{
- std::stringstream ss("");
+ infodisplay_str.clear();
if (infoDisplay.watermark)
{
- ss << "Wicked Engine " << wiVersion::GetVersionString() << " ";
+ infodisplay_str += "Wicked Engine ";
+ infodisplay_str += wiVersion::GetVersionString();
+ infodisplay_str += " ";
#if defined(_ARM)
- ss << "[ARM]";
+ infodisplay_str += "[ARM]";
#elif defined(_WIN64)
- ss << "[64-bit]";
+ infodisplay_str += "[64-bit]";
#elif defined(_WIN32)
- ss << "[32-bit]";
+ infodisplay_str += "[32-bit]";
#endif
#ifdef PLATFORM_UWP
- ss << "[UWP]";
+ infodisplay_str += "[UWP]";
#endif
#ifdef WICKEDENGINE_BUILD_DX12
if (dynamic_cast(graphicsDevice.get()))
{
- ss << "[DX12]";
+ infodisplay_str += "[DX12]";
}
#endif
#ifdef WICKEDENGINE_BUILD_VULKAN
if (dynamic_cast(graphicsDevice.get()))
{
- ss << "[Vulkan]";
+ infodisplay_str += "[Vulkan]";
}
#endif
#ifdef _DEBUG
- ss << "[DEBUG]";
+ infodisplay_str += "[DEBUG]";
#endif
if (graphicsDevice->IsDebugDevice())
{
- ss << "[debugdevice]";
+ infodisplay_str += "[debugdevice]";
}
- ss << std::endl;
+ infodisplay_str += "\n";
}
if (infoDisplay.resolution)
{
- ss << "Resolution: " << canvas.GetPhysicalWidth() << " x " << canvas.GetPhysicalHeight() << " (" << canvas.GetDPI() << " dpi)" << std::endl;
+ infodisplay_str += "Resolution: " + std::to_string(canvas.GetPhysicalWidth()) + " x " + std::to_string(canvas.GetPhysicalHeight()) + " (" + std::to_string(int(canvas.GetDPI())) + " dpi)\n";
}
if (infoDisplay.logical_size)
{
- ss << "Logical Size: " << canvas.GetLogicalWidth() << " x " << canvas.GetLogicalHeight() << std::endl;
+ infodisplay_str += "Logical Size: " + std::to_string(int(canvas.GetLogicalWidth())) + " x " + std::to_string(int(canvas.GetLogicalHeight())) + "\n";
}
if (infoDisplay.colorspace)
{
- ss << "Color Space: ";
+ infodisplay_str += "Color Space: ";
ColorSpace colorSpace = graphicsDevice->GetSwapChainColorSpace(&swapChain);
switch (colorSpace)
{
default:
case wiGraphics::ColorSpace::SRGB:
- ss << "sRGB";
+ infodisplay_str += "sRGB";
break;
case wiGraphics::ColorSpace::HDR10_ST2084:
- ss << "ST.2084 (HDR10)";
+ infodisplay_str += "ST.2084 (HDR10)";
break;
case wiGraphics::ColorSpace::HDR_LINEAR:
- ss << "Linear (HDR)";
+ infodisplay_str += "Linear (HDR)";
break;
}
- ss << std::endl;
+ infodisplay_str += "\n";
}
if (infoDisplay.fpsinfo)
{
@@ -354,29 +358,28 @@ void MainComponent::Compose(CommandList cmd)
displaydeltatime = avg_time / arraysize(deltatimes);
}
- ss.precision(2);
- ss << std::fixed << 1.0f / displaydeltatime << " FPS" << std::endl;
+ infodisplay_str += std::to_string(int(std::round(1.0f / displaydeltatime))) + " FPS\n";
}
if (infoDisplay.heap_allocation_counter)
{
- ss << "Heap allocations per frame: " << number_of_heap_allocations.load() << std::endl;
+ infodisplay_str += "Heap allocations per frame: " + std::to_string(number_of_heap_allocations.load()) + " (" + std::to_string(size_of_heap_allocations.load()) + " bytes)\n";
number_of_heap_allocations.store(0);
+ size_of_heap_allocations.store(0);
}
if (infoDisplay.pipeline_count)
{
- ss << "Graphics pipelines active: " << graphicsDevice->GetActivePipelineCount() << std::endl;
+ infodisplay_str += "Graphics pipelines active: " + std::to_string(graphicsDevice->GetActivePipelineCount()) + "\n";
}
#ifdef _DEBUG
- ss << "Warning: This is a [DEBUG] build, performance will be slow!" << std::endl;
+ infodisplay_str += "Warning: This is a [DEBUG] build, performance will be slow!\n";
#endif
if (graphicsDevice->IsDebugDevice())
{
- ss << "Warning: Graphics is in [debugdevice] mode, performance will be slow!" << std::endl;
+ infodisplay_str += "Warning: Graphics is in [debugdevice] mode, performance will be slow!\n";
}
- ss.precision(2);
- wiFont::Draw(ss.str(), wiFontParams(4, 4, infoDisplay.size, WIFALIGN_LEFT, WIFALIGN_TOP, wiColor(255,255,255,255), wiColor(0,0,0,255)), cmd);
+ wiFont::Draw(infodisplay_str, wiFontParams(4, 4, infoDisplay.size, WIFALIGN_LEFT, WIFALIGN_TOP, wiColor(255,255,255,255), wiColor(0,0,0,255)), cmd);
if (infoDisplay.colorgrading_helper)
{
@@ -424,7 +427,7 @@ void MainComponent::SetWindow(wiPlatform::window_type window, bool fullscreen)
#elif defined(WICKEDENGINE_BUILD_VULKAN)
use_vulkan = true;
#else
- wiBackLog::post("No rendering backend is enabled! Please enable at least one so we can use it as default");
+ wiBackLog::post("No rendering backend is enabled! Please enable at least one so we can use it as default", wiBackLog::LogLevel::Error);
assert(false);
#endif
}
@@ -500,22 +503,26 @@ void MainComponent::SetWindow(wiPlatform::window_type window, bool fullscreen)
void* operator new(std::size_t size) {
number_of_heap_allocations.fetch_add(1);
+ size_of_heap_allocations.fetch_add(size);
void* p = malloc(size);
if (!p) throw std::bad_alloc();
return p;
}
void* operator new[](std::size_t size) {
number_of_heap_allocations.fetch_add(1);
+ size_of_heap_allocations.fetch_add(size);
void* p = malloc(size);
if (!p) throw std::bad_alloc();
return p;
}
void* operator new[](std::size_t size, const std::nothrow_t&) throw() {
number_of_heap_allocations.fetch_add(1);
+ size_of_heap_allocations.fetch_add(size);
return malloc(size);
}
void* operator new(std::size_t size, const std::nothrow_t&) throw() {
number_of_heap_allocations.fetch_add(1);
+ size_of_heap_allocations.fetch_add(size);
return malloc(size);
}
void operator delete(void* ptr) throw() { free(ptr); }
diff --git a/WickedEngine/MainComponent.h b/WickedEngine/MainComponent.h
index 14666f4d5..fc07d58ad 100644
--- a/WickedEngine/MainComponent.h
+++ b/WickedEngine/MainComponent.h
@@ -9,6 +9,7 @@
#include "wiCanvas.h"
#include
+#include
class RenderPath;
@@ -38,6 +39,8 @@ protected:
wiGraphics::Texture rendertarget;
wiGraphics::RenderPass renderpass;
+ std::string infodisplay_str;
+
public:
virtual ~MainComponent() = default;
diff --git a/WickedEngine/MainComponent_BindLua.cpp b/WickedEngine/MainComponent_BindLua.cpp
index 6f872cc74..dc27291dd 100644
--- a/WickedEngine/MainComponent_BindLua.cpp
+++ b/WickedEngine/MainComponent_BindLua.cpp
@@ -17,7 +17,9 @@ Luna::FunctionType MainComponent_BindLua::methods[] = {
lunamethod(MainComponent_BindLua, SetWatermarkDisplay),
lunamethod(MainComponent_BindLua, SetFPSDisplay),
lunamethod(MainComponent_BindLua, SetResolutionDisplay),
+ lunamethod(MainComponent_BindLua, SetLogicalSizeDisplay),
lunamethod(MainComponent_BindLua, SetPipelineCountDisplay),
+ lunamethod(MainComponent_BindLua, SetHeapAllocationCountDisplay),
lunamethod(MainComponent_BindLua, GetCanvas),
{ NULL, NULL }
};
@@ -257,6 +259,22 @@ int MainComponent_BindLua::SetResolutionDisplay(lua_State *L)
wiLua::SError(L, "SetResolutionDisplay(bool active) not enough arguments!");
return 0;
}
+int MainComponent_BindLua::SetLogicalSizeDisplay(lua_State* L)
+{
+ if (component == nullptr)
+ {
+ wiLua::SError(L, "SetLogicalSizeDisplay() component is empty!");
+ return 0;
+ }
+ int argc = wiLua::SGetArgCount(L);
+ if (argc > 0)
+ {
+ component->infoDisplay.logical_size = wiLua::SGetBool(L, 1);
+ }
+ else
+ wiLua::SError(L, "SetLogicalSizeDisplay(bool active) not enough arguments!");
+ return 0;
+}
int MainComponent_BindLua::SetPipelineCountDisplay(lua_State *L)
{
if (component == nullptr)
@@ -273,6 +291,22 @@ int MainComponent_BindLua::SetPipelineCountDisplay(lua_State *L)
wiLua::SError(L, "SetPipelineCountDisplay(bool active) not enough arguments!");
return 0;
}
+int MainComponent_BindLua::SetHeapAllocationCountDisplay(lua_State* L)
+{
+ if (component == nullptr)
+ {
+ wiLua::SError(L, "SetHeapAllocationCountDisplay() component is empty!");
+ return 0;
+ }
+ int argc = wiLua::SGetArgCount(L);
+ if (argc > 0)
+ {
+ component->infoDisplay.heap_allocation_counter = wiLua::SGetBool(L, 1);
+ }
+ else
+ wiLua::SError(L, "SetHeapAllocationCountDisplay(bool active) not enough arguments!");
+ return 0;
+}
int MainComponent_BindLua::GetCanvas(lua_State* L)
{
diff --git a/WickedEngine/MainComponent_BindLua.h b/WickedEngine/MainComponent_BindLua.h
index 0c4cc580f..a64f862a2 100644
--- a/WickedEngine/MainComponent_BindLua.h
+++ b/WickedEngine/MainComponent_BindLua.h
@@ -44,8 +44,10 @@ public:
int SetInfoDisplay(lua_State *L);
int SetWatermarkDisplay(lua_State *L);
int SetFPSDisplay(lua_State *L);
- int SetResolutionDisplay(lua_State *L);
+ int SetResolutionDisplay(lua_State* L);
+ int SetLogicalSizeDisplay(lua_State *L);
int SetPipelineCountDisplay(lua_State* L);
+ int SetHeapAllocationCountDisplay(lua_State* L);
int GetCanvas(lua_State* L);
diff --git a/WickedEngine/RenderPath2D.cpp b/WickedEngine/RenderPath2D.cpp
index aacd6e6b0..e3a6df56b 100644
--- a/WickedEngine/RenderPath2D.cpp
+++ b/WickedEngine/RenderPath2D.cpp
@@ -536,7 +536,7 @@ void RenderPath2D::CleanLayers()
{
continue;
}
- std::vector itemsToRetain(0);
+ wi::vector itemsToRetain(0);
for (auto& y : x.items)
{
if (y.sprite != nullptr || y.font!=nullptr)
diff --git a/WickedEngine/RenderPath2D.h b/WickedEngine/RenderPath2D.h
index b8b8edc8d..728dd82ec 100644
--- a/WickedEngine/RenderPath2D.h
+++ b/WickedEngine/RenderPath2D.h
@@ -1,6 +1,7 @@
#pragma once
#include "RenderPath.h"
#include "wiGUI.h"
+#include "wiVector.h"
#include
@@ -23,7 +24,7 @@ struct RenderItem2D
};
struct RenderLayer2D
{
- std::vector items;
+ wi::vector items;
std::string name;
int order = 0;
};
@@ -76,7 +77,7 @@ public:
void ClearFonts();
int GetFontOrder(wiSpriteFont* font);
- std::vector layers{ 1 };
+ wi::vector layers{ 1 };
void AddLayer(const std::string& name);
void SetLayerOrder(const std::string& name, int order);
void SetSpriteOrder(wiSprite* sprite, int order);
diff --git a/WickedEngine/RenderPath2D_BindLua.cpp b/WickedEngine/RenderPath2D_BindLua.cpp
index 4eab50d16..4508043ca 100644
--- a/WickedEngine/RenderPath2D_BindLua.cpp
+++ b/WickedEngine/RenderPath2D_BindLua.cpp
@@ -2,7 +2,7 @@
#include "wiSprite_BindLua.h"
#include "wiSpriteFont_BindLua.h"
-#include
+#include
const char RenderPath2D_BindLua::className[] = "RenderPath2D";
@@ -302,12 +302,12 @@ int RenderPath2D_BindLua::GetLayers(lua_State* L)
RenderPath2D* ccomp = dynamic_cast(component);
if (ccomp != nullptr)
{
- std::stringstream ss("");
+ std::string ss;
for (auto& x : ccomp->layers)
{
- ss << x.name << std::endl;
+ ss += x.name + "\n";
}
- wiLua::SSetString(L, ss.str());
+ wiLua::SSetString(L, ss);
return 1;
}
else
diff --git a/WickedEngine/RenderPath3D_PathTracing.cpp b/WickedEngine/RenderPath3D_PathTracing.cpp
index 5a2fc8a8d..477524468 100644
--- a/WickedEngine/RenderPath3D_PathTracing.cpp
+++ b/WickedEngine/RenderPath3D_PathTracing.cpp
@@ -215,7 +215,7 @@ void RenderPath3D_PathTracing::Update(float dt)
auto error = device.getError(errorMessage);
if (error != oidn::Error::None && error != oidn::Error::Cancelled)
{
- wiBackLog::post((std::string("[OpenImageDenoise error] ") + errorMessage).c_str());
+ wiBackLog::post(std::string("[OpenImageDenoise error] ") + errorMessage);
}
}
diff --git a/WickedEngine/RenderPath3D_PathTracing.h b/WickedEngine/RenderPath3D_PathTracing.h
index 4644a26d3..7fe4c6223 100644
--- a/WickedEngine/RenderPath3D_PathTracing.h
+++ b/WickedEngine/RenderPath3D_PathTracing.h
@@ -1,6 +1,6 @@
#pragma once
#include "RenderPath3D.h"
-
+#include "wiVector.h"
class RenderPath3D_PathTracing :
public RenderPath3D
@@ -10,10 +10,10 @@ protected:
int target = 1024;
wiGraphics::Texture traceResult;
- std::vector texturedata_src;
- std::vector texturedata_dst;
- std::vector texturedata_albedo;
- std::vector texturedata_normal;
+ wi::vector texturedata_src;
+ wi::vector texturedata_dst;
+ wi::vector texturedata_albedo;
+ wi::vector texturedata_normal;
wiGraphics::Texture denoiserAlbedo;
wiGraphics::Texture denoiserNormal;
wiGraphics::Texture denoiserResult;
diff --git a/WickedEngine/Utility/flat_hash_map.hpp b/WickedEngine/Utility/flat_hash_map.hpp
new file mode 100644
index 000000000..633bd4b47
--- /dev/null
+++ b/WickedEngine/Utility/flat_hash_map.hpp
@@ -0,0 +1,1497 @@
+// Copyright Malte Skarupke 2017.
+// Distributed under the Boost Software License, Version 1.0.
+// (See http://www.boost.org/LICENSE_1_0.txt)
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef _MSC_VER
+#define SKA_NOINLINE(...) __declspec(noinline) __VA_ARGS__
+#else
+#define SKA_NOINLINE(...) __VA_ARGS__ __attribute__((noinline))
+#endif
+
+namespace ska
+{
+struct prime_number_hash_policy;
+struct power_of_two_hash_policy;
+struct fibonacci_hash_policy;
+
+namespace detailv3
+{
+template
+struct functor_storage : Functor
+{
+ functor_storage() = default;
+ functor_storage(const Functor & functor)
+ : Functor(functor)
+ {
+ }
+ template
+ Result operator()(Args &&... args)
+ {
+ return static_cast(*this)(std::forward(args)...);
+ }
+ template
+ Result operator()(Args &&... args) const
+ {
+ return static_cast(*this)(std::forward(args)...);
+ }
+};
+template
+struct functor_storage
+{
+ typedef Result (*function_ptr)(Args...);
+ function_ptr function;
+ functor_storage(function_ptr function)
+ : function(function)
+ {
+ }
+ Result operator()(Args... args) const
+ {
+ return function(std::forward(args)...);
+ }
+ operator function_ptr &()
+ {
+ return function;
+ }
+ operator const function_ptr &()
+ {
+ return function;
+ }
+};
+template
+struct KeyOrValueHasher : functor_storage
+{
+ typedef functor_storage hasher_storage;
+ KeyOrValueHasher() = default;
+ KeyOrValueHasher(const hasher & hash)
+ : hasher_storage(hash)
+ {
+ }
+ size_t operator()(const key_type & key)
+ {
+ return static_cast(*this)(key);
+ }
+ size_t operator()(const key_type & key) const
+ {
+ return static_cast(*this)(key);
+ }
+ size_t operator()(const value_type & value)
+ {
+ return static_cast(*this)(value.first);
+ }
+ size_t operator()(const value_type & value) const
+ {
+ return static_cast(*this)(value.first);
+ }
+ template
+ size_t operator()(const std::pair & value)
+ {
+ return static_cast(*this)(value.first);
+ }
+ template
+ size_t operator()(const std::pair & value) const
+ {
+ return static_cast(*this)(value.first);
+ }
+};
+template
+struct KeyOrValueEquality : functor_storage
+{
+ typedef functor_storage equality_storage;
+ KeyOrValueEquality() = default;
+ KeyOrValueEquality(const key_equal & equality)
+ : equality_storage(equality)
+ {
+ }
+ bool operator()(const key_type & lhs, const key_type & rhs)
+ {
+ return static_cast(*this)(lhs, rhs);
+ }
+ bool operator()(const key_type & lhs, const value_type & rhs)
+ {
+ return static_cast(*this)(lhs, rhs.first);
+ }
+ bool operator()(const value_type & lhs, const key_type & rhs)
+ {
+ return static_cast(*this)(lhs.first, rhs);
+ }
+ bool operator()(const value_type & lhs, const value_type & rhs)
+ {
+ return static_cast(*this)(lhs.first, rhs.first);
+ }
+ template
+ bool operator()(const key_type & lhs, const std::pair & rhs)
+ {
+ return static_cast(*this)(lhs, rhs.first);
+ }
+ template
+ bool operator()(const std::pair & lhs, const key_type & rhs)
+ {
+ return static_cast(*this)(lhs.first, rhs);
+ }
+ template
+ bool operator()(const value_type & lhs, const std::pair & rhs)
+ {
+ return static_cast(*this)(lhs.first, rhs.first);
+ }
+ template
+ bool operator()(const std::pair & lhs, const value_type & rhs)
+ {
+ return static_cast(*this)(lhs.first, rhs.first);
+ }
+ template
+ bool operator()(const std::pair & lhs, const std::pair & rhs)
+ {
+ return static_cast(*this)(lhs.first, rhs.first);
+ }
+};
+static constexpr int8_t min_lookups = 4;
+template
+struct sherwood_v3_entry
+{
+ sherwood_v3_entry()
+ {
+ }
+ sherwood_v3_entry(int8_t distance_from_desired)
+ : distance_from_desired(distance_from_desired)
+ {
+ }
+ ~sherwood_v3_entry()
+ {
+ }
+ static sherwood_v3_entry * empty_default_table()
+ {
+ static sherwood_v3_entry result[min_lookups] = { {}, {}, {}, {special_end_value} };
+ return result;
+ }
+
+ bool has_value() const
+ {
+ return distance_from_desired >= 0;
+ }
+ bool is_empty() const
+ {
+ return distance_from_desired < 0;
+ }
+ bool is_at_desired_position() const
+ {
+ return distance_from_desired <= 0;
+ }
+ template
+ void emplace(int8_t distance, Args &&... args)
+ {
+ new (std::addressof(value)) T(std::forward(args)...);
+ distance_from_desired = distance;
+ }
+
+ void destroy_value()
+ {
+ value.~T();
+ distance_from_desired = -1;
+ }
+
+ int8_t distance_from_desired = -1;
+ static constexpr int8_t special_end_value = 0;
+ union { T value; };
+};
+
+inline int8_t log2(size_t value)
+{
+ static constexpr int8_t table[64] =
+ {
+ 63, 0, 58, 1, 59, 47, 53, 2,
+ 60, 39, 48, 27, 54, 33, 42, 3,
+ 61, 51, 37, 40, 49, 18, 28, 20,
+ 55, 30, 34, 11, 43, 14, 22, 4,
+ 62, 57, 46, 52, 38, 26, 32, 41,
+ 50, 36, 17, 19, 29, 10, 13, 21,
+ 56, 45, 25, 31, 35, 16, 9, 12,
+ 44, 24, 15, 8, 23, 7, 6, 5
+ };
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ value |= value >> 32;
+ return table[((value - (value >> 1)) * 0x07EDD5E59A4E28C2) >> 58];
+}
+
+template
+struct AssignIfTrue
+{
+ void operator()(T & lhs, const T & rhs)
+ {
+ lhs = rhs;
+ }
+ void operator()(T & lhs, T && rhs)
+ {
+ lhs = std::move(rhs);
+ }
+};
+template
+struct AssignIfTrue
+{
+ void operator()(T &, const T &)
+ {
+ }
+ void operator()(T &, T &&)
+ {
+ }
+};
+
+inline size_t next_power_of_two(size_t i)
+{
+ --i;
+ i |= i >> 1;
+ i |= i >> 2;
+ i |= i >> 4;
+ i |= i >> 8;
+ i |= i >> 16;
+ i |= i >> 32;
+ ++i;
+ return i;
+}
+
+template using void_t = void;
+
+template
+struct HashPolicySelector
+{
+ typedef fibonacci_hash_policy type;
+};
+template
+struct HashPolicySelector>
+{
+ typedef typename T::hash_policy type;
+};
+
+template
+class sherwood_v3_table : private EntryAlloc, private Hasher, private Equal
+{
+ using Entry = detailv3::sherwood_v3_entry;
+ using AllocatorTraits = std::allocator_traits;
+ using EntryPointer = typename AllocatorTraits::pointer;
+ struct convertible_to_iterator;
+
+public:
+
+ using value_type = T;
+ using size_type = size_t;
+ using difference_type = std::ptrdiff_t;
+ using hasher = ArgumentHash;
+ using key_equal = ArgumentEqual;
+ using allocator_type = EntryAlloc;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+
+ sherwood_v3_table()
+ {
+ }
+ explicit sherwood_v3_table(size_type bucket_count, const ArgumentHash & hash = ArgumentHash(), const ArgumentEqual & equal = ArgumentEqual(), const ArgumentAlloc & alloc = ArgumentAlloc())
+ : EntryAlloc(alloc), Hasher(hash), Equal(equal)
+ {
+ rehash(bucket_count);
+ }
+ sherwood_v3_table(size_type bucket_count, const ArgumentAlloc & alloc)
+ : sherwood_v3_table(bucket_count, ArgumentHash(), ArgumentEqual(), alloc)
+ {
+ }
+ sherwood_v3_table(size_type bucket_count, const ArgumentHash & hash, const ArgumentAlloc & alloc)
+ : sherwood_v3_table(bucket_count, hash, ArgumentEqual(), alloc)
+ {
+ }
+ explicit sherwood_v3_table(const ArgumentAlloc & alloc)
+ : EntryAlloc(alloc)
+ {
+ }
+ template
+ sherwood_v3_table(It first, It last, size_type bucket_count = 0, const ArgumentHash & hash = ArgumentHash(), const ArgumentEqual & equal = ArgumentEqual(), const ArgumentAlloc & alloc = ArgumentAlloc())
+ : sherwood_v3_table(bucket_count, hash, equal, alloc)
+ {
+ insert(first, last);
+ }
+ template
+ sherwood_v3_table(It first, It last, size_type bucket_count, const ArgumentAlloc & alloc)
+ : sherwood_v3_table(first, last, bucket_count, ArgumentHash(), ArgumentEqual(), alloc)
+ {
+ }
+ template
+ sherwood_v3_table(It first, It last, size_type bucket_count, const ArgumentHash & hash, const ArgumentAlloc & alloc)
+ : sherwood_v3_table(first, last, bucket_count, hash, ArgumentEqual(), alloc)
+ {
+ }
+ sherwood_v3_table(std::initializer_list il, size_type bucket_count = 0, const ArgumentHash & hash = ArgumentHash(), const ArgumentEqual & equal = ArgumentEqual(), const ArgumentAlloc & alloc = ArgumentAlloc())
+ : sherwood_v3_table(bucket_count, hash, equal, alloc)
+ {
+ if (bucket_count == 0)
+ rehash(il.size());
+ insert(il.begin(), il.end());
+ }
+ sherwood_v3_table(std::initializer_list il, size_type bucket_count, const ArgumentAlloc & alloc)
+ : sherwood_v3_table(il, bucket_count, ArgumentHash(), ArgumentEqual(), alloc)
+ {
+ }
+ sherwood_v3_table(std::initializer_list il, size_type bucket_count, const ArgumentHash & hash, const ArgumentAlloc & alloc)
+ : sherwood_v3_table(il, bucket_count, hash, ArgumentEqual(), alloc)
+ {
+ }
+ sherwood_v3_table(const sherwood_v3_table & other)
+ : sherwood_v3_table(other, AllocatorTraits::select_on_container_copy_construction(other.get_allocator()))
+ {
+ }
+ sherwood_v3_table(const sherwood_v3_table & other, const ArgumentAlloc & alloc)
+ : EntryAlloc(alloc), Hasher(other), Equal(other), _max_load_factor(other._max_load_factor)
+ {
+ rehash_for_other_container(other);
+ try
+ {
+ insert(other.begin(), other.end());
+ }
+ catch(...)
+ {
+ clear();
+ deallocate_data(entries, num_slots_minus_one, max_lookups);
+ throw;
+ }
+ }
+ sherwood_v3_table(sherwood_v3_table && other) noexcept
+ : EntryAlloc(std::move(other)), Hasher(std::move(other)), Equal(std::move(other))
+ {
+ swap_pointers(other);
+ }
+ sherwood_v3_table(sherwood_v3_table && other, const ArgumentAlloc & alloc) noexcept
+ : EntryAlloc(alloc), Hasher(std::move(other)), Equal(std::move(other))
+ {
+ swap_pointers(other);
+ }
+ sherwood_v3_table & operator=(const sherwood_v3_table & other)
+ {
+ if (this == std::addressof(other))
+ return *this;
+
+ clear();
+ if (AllocatorTraits::propagate_on_container_copy_assignment::value)
+ {
+ if (static_cast(*this) != static_cast(other))
+ {
+ reset_to_empty_state();
+ }
+ AssignIfTrue()(*this, other);
+ }
+ _max_load_factor = other._max_load_factor;
+ static_cast(*this) = other;
+ static_cast(*this) = other;
+ rehash_for_other_container(other);
+ insert(other.begin(), other.end());
+ return *this;
+ }
+ sherwood_v3_table & operator=(sherwood_v3_table && other) noexcept
+ {
+ if (this == std::addressof(other))
+ return *this;
+ else if (AllocatorTraits::propagate_on_container_move_assignment::value)
+ {
+ clear();
+ reset_to_empty_state();
+ AssignIfTrue()(*this, std::move(other));
+ swap_pointers(other);
+ }
+ else if (static_cast(*this) == static_cast(other))
+ {
+ swap_pointers(other);
+ }
+ else
+ {
+ clear();
+ _max_load_factor = other._max_load_factor;
+ rehash_for_other_container(other);
+ for (T & elem : other)
+ emplace(std::move(elem));
+ other.clear();
+ }
+ static_cast(*this) = std::move(other);
+ static_cast(*this) = std::move(other);
+ return *this;
+ }
+ ~sherwood_v3_table()
+ {
+ clear();
+ deallocate_data(entries, num_slots_minus_one, max_lookups);
+ }
+
+ const allocator_type & get_allocator() const
+ {
+ return static_cast(*this);
+ }
+ const ArgumentEqual & key_eq() const
+ {
+ return static_cast(*this);
+ }
+ const ArgumentHash & hash_function() const
+ {
+ return static_cast(*this);
+ }
+
+ template
+ struct templated_iterator
+ {
+ templated_iterator() = default;
+ templated_iterator(EntryPointer current)
+ : current(current)
+ {
+ }
+ EntryPointer current = EntryPointer();
+
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = ValueType;
+ using difference_type = ptrdiff_t;
+ using pointer = ValueType *;
+ using reference = ValueType &;
+
+ friend bool operator==(const templated_iterator & lhs, const templated_iterator & rhs)
+ {
+ return lhs.current == rhs.current;
+ }
+ friend bool operator!=(const templated_iterator & lhs, const templated_iterator & rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ templated_iterator & operator++()
+ {
+ do
+ {
+ ++current;
+ }
+ while(current->is_empty());
+ return *this;
+ }
+ templated_iterator operator++(int)
+ {
+ templated_iterator copy(*this);
+ ++*this;
+ return copy;
+ }
+
+ ValueType & operator*() const
+ {
+ return current->value;
+ }
+ ValueType * operator->() const
+ {
+ return std::addressof(current->value);
+ }
+
+ operator templated_iterator() const
+ {
+ return { current };
+ }
+ };
+ using iterator = templated_iterator;
+ using const_iterator = templated_iterator;
+
+ iterator begin()
+ {
+ for (EntryPointer it = entries;; ++it)
+ {
+ if (it->has_value())
+ return { it };
+ }
+ }
+ const_iterator begin() const
+ {
+ for (EntryPointer it = entries;; ++it)
+ {
+ if (it->has_value())
+ return { it };
+ }
+ }
+ const_iterator cbegin() const
+ {
+ return begin();
+ }
+ iterator end()
+ {
+ return { entries + static_cast(num_slots_minus_one + max_lookups) };
+ }
+ const_iterator end() const
+ {
+ return { entries + static_cast(num_slots_minus_one + max_lookups) };
+ }
+ const_iterator cend() const
+ {
+ return end();
+ }
+
+ iterator find(const FindKey & key)
+ {
+ size_t index = hash_policy.index_for_hash(hash_object(key), num_slots_minus_one);
+ EntryPointer it = entries + ptrdiff_t(index);
+ for (int8_t distance = 0; it->distance_from_desired >= distance; ++distance, ++it)
+ {
+ if (compares_equal(key, it->value))
+ return { it };
+ }
+ return end();
+ }
+ const_iterator find(const FindKey & key) const
+ {
+ return const_cast(this)->find(key);
+ }
+ size_t count(const FindKey & key) const
+ {
+ return find(key) == end() ? 0 : 1;
+ }
+ std::pair equal_range(const FindKey & key)
+ {
+ iterator found = find(key);
+ if (found == end())
+ return { found, found };
+ else
+ return { found, std::next(found) };
+ }
+ std::pair equal_range(const FindKey & key) const
+ {
+ const_iterator found = find(key);
+ if (found == end())
+ return { found, found };
+ else
+ return { found, std::next(found) };
+ }
+
+ template
+ std::pair emplace(Key && key, Args &&... args)
+ {
+ size_t index = hash_policy.index_for_hash(hash_object(key), num_slots_minus_one);
+ EntryPointer current_entry = entries + ptrdiff_t(index);
+ int8_t distance_from_desired = 0;
+ for (; current_entry->distance_from_desired >= distance_from_desired; ++current_entry, ++distance_from_desired)
+ {
+ if (compares_equal(key, current_entry->value))
+ return { { current_entry }, false };
+ }
+ return emplace_new_key(distance_from_desired, current_entry, std::forward